mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-21 06:18:42 +02:00
Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-66-open-app-from-qr-code
Conflicts: lib/di.dart lib/src/screens/send/send_page.dart lib/src/screens/send/widgets/send_card.dart lib/utils/payment_request.dart res/values/strings_de.arb res/values/strings_en.arb res/values/strings_es.arb res/values/strings_fr.arb res/values/strings_hi.arb res/values/strings_hr.arb res/values/strings_it.arb res/values/strings_ja.arb res/values/strings_ko.arb res/values/strings_nl.arb res/values/strings_pl.arb res/values/strings_pt.arb res/values/strings_ru.arb res/values/strings_uk.arb res/values/strings_zh.arb
This commit is contained in:
@@ -6,14 +6,14 @@ import 'package:cake_wallet/monero/monero.dart';
|
||||
|
||||
class AnyPayPayment {
|
||||
AnyPayPayment({
|
||||
@required this.time,
|
||||
@required this.expires,
|
||||
@required this.memo,
|
||||
@required this.paymentUrl,
|
||||
@required this.paymentId,
|
||||
@required this.chain,
|
||||
@required this.network,
|
||||
@required this.instructions});
|
||||
required this.time,
|
||||
required this.expires,
|
||||
required this.memo,
|
||||
required this.paymentUrl,
|
||||
required this.paymentId,
|
||||
required this.chain,
|
||||
required this.network,
|
||||
required this.instructions});
|
||||
|
||||
factory AnyPayPayment.fromMap(Map<String, dynamic> obj) {
|
||||
final instructions = (obj['instructions'] as List<dynamic>)
|
||||
@@ -45,13 +45,13 @@ class AnyPayPayment {
|
||||
.fold<int>(0, (int outAcc, out) => outAcc + out.amount));
|
||||
switch (chain) {
|
||||
case AnyPayChain.xmr:
|
||||
return monero.formatterMoneroAmountToString(amount: total);
|
||||
return monero!.formatterMoneroAmountToString(amount: total);
|
||||
case AnyPayChain.btc:
|
||||
return bitcoin.formatterBitcoinAmountToString(amount: total);
|
||||
return bitcoin!.formatterBitcoinAmountToString(amount: total);
|
||||
case AnyPayChain.ltc:
|
||||
return bitcoin.formatterBitcoinAmountToString(amount: total);
|
||||
return bitcoin!.formatterBitcoinAmountToString(amount: total);
|
||||
default:
|
||||
return null;
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ import 'package:cake_wallet/anypay/any_pay_trasnaction.dart';
|
||||
|
||||
class AnyPayPaymentCommittedInfo {
|
||||
const AnyPayPaymentCommittedInfo({
|
||||
@required this.uri,
|
||||
@required this.currency,
|
||||
@required this.chain,
|
||||
@required this.transactions,
|
||||
@required this.memo});
|
||||
required this.uri,
|
||||
required this.currency,
|
||||
required this.chain,
|
||||
required this.transactions,
|
||||
required this.memo});
|
||||
|
||||
final String uri;
|
||||
final String currency;
|
||||
|
||||
@@ -3,11 +3,11 @@ import 'package:cake_wallet/anypay/any_pay_payment_instruction_output.dart';
|
||||
|
||||
class AnyPayPaymentInstruction {
|
||||
AnyPayPaymentInstruction({
|
||||
@required this.type,
|
||||
@required this.requiredFeeRate,
|
||||
@required this.txKey,
|
||||
@required this.txHash,
|
||||
@required this.outputs});
|
||||
required this.type,
|
||||
required this.requiredFeeRate,
|
||||
required this.txKey,
|
||||
required this.txHash,
|
||||
required this.outputs});
|
||||
|
||||
factory AnyPayPaymentInstruction.fromMap(Map<String, dynamic> obj) {
|
||||
final outputs = (obj['outputs'] as List<dynamic>)
|
||||
@@ -17,8 +17,8 @@ class AnyPayPaymentInstruction {
|
||||
return AnyPayPaymentInstruction(
|
||||
type: obj['type'] as String,
|
||||
requiredFeeRate: obj['requiredFeeRate'] as int,
|
||||
txKey: obj['tx_key'] as bool,
|
||||
txHash: obj['tx_hash'] as bool,
|
||||
txKey: obj['tx_key'] as bool? ?? false,
|
||||
txHash: obj['tx_hash'] as bool? ?? false,
|
||||
outputs: outputs);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class AnyPayTransaction {
|
||||
const AnyPayTransaction(this.tx, {@required this.id, @required this.key});
|
||||
const AnyPayTransaction(this.tx, {required this.id, required this.key});
|
||||
|
||||
final String tx;
|
||||
final String id;
|
||||
final String key;
|
||||
final String? key;
|
||||
}
|
||||
+20
-14
@@ -5,11 +5,13 @@ import 'package:http/http.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/anypay/any_pay_payment.dart';
|
||||
import 'package:cake_wallet/anypay/any_pay_trasnaction.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
|
||||
class AnyPayApi {
|
||||
static const contentTypePaymentRequest = 'application/payment-request';
|
||||
static const contentTypePayment = 'application/payment';
|
||||
static const xPayproVersion = '2';
|
||||
static const anypayToken = secrets.anypayToken;
|
||||
|
||||
static String chainByScheme(String scheme) {
|
||||
switch (scheme.toLowerCase()) {
|
||||
@@ -33,45 +35,49 @@ class AnyPayApi {
|
||||
case 'litecoin':
|
||||
return CryptoCurrency.ltc;
|
||||
default:
|
||||
return null;
|
||||
throw Exception('Unexpected scheme: ${scheme}');
|
||||
}
|
||||
}
|
||||
|
||||
Future<AnyPayPayment> paymentRequest(String uri) async {
|
||||
final fragments = uri.split(':?r=');
|
||||
final scheme = fragments.first;
|
||||
final url = fragments[1];
|
||||
final headers = <String, String>{
|
||||
final url = Uri.parse(fragments[1]);
|
||||
final headers = <String, String>{
|
||||
'Content-Type': contentTypePaymentRequest,
|
||||
'X-Paypro-Version': xPayproVersion,
|
||||
'Accept': '*/*',};
|
||||
'Accept': '*/*',
|
||||
'x-wallet': 'cake',
|
||||
'x-wallet-token': anypayToken,};
|
||||
final body = <String, dynamic>{
|
||||
'chain': chainByScheme(scheme),
|
||||
'currency': currencyByScheme(scheme).title};
|
||||
final response = await post(url, headers: headers, body: utf8.encode(json.encode(body)));
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return null;
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected response http code: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final decodedBody = json.decode(response.body) as Map<String, dynamic>;
|
||||
return AnyPayPayment.fromMap(decodedBody);
|
||||
final decodedBody = json.decode(response.body) as Map<String, dynamic>;
|
||||
return AnyPayPayment.fromMap(decodedBody);
|
||||
}
|
||||
|
||||
Future<AnyPayPaymentCommittedInfo> payment(
|
||||
String uri,
|
||||
{@required String chain,
|
||||
@required String currency,
|
||||
@required List<AnyPayTransaction> transactions}) async {
|
||||
final headers = <String, String>{
|
||||
{required String chain,
|
||||
required String currency,
|
||||
required List<AnyPayTransaction> transactions}) async {
|
||||
final headers = <String, String>{
|
||||
'Content-Type': contentTypePayment,
|
||||
'X-Paypro-Version': xPayproVersion,
|
||||
'Accept': '*/*',};
|
||||
'Accept': '*/*',
|
||||
'x-wallet': 'cake',
|
||||
'x-wallet-token': anypayToken,};
|
||||
final body = <String, dynamic>{
|
||||
'chain': chain,
|
||||
'currency': currency,
|
||||
'transactions': transactions.map((tx) => {'tx': tx.tx, 'tx_hash': tx.id, 'tx_key': tx.key}).toList()};
|
||||
final response = await post(uri, headers: headers, body: utf8.encode(json.encode(body)));
|
||||
final response = await post(Uri.parse(uri), headers: headers, body: utf8.encode(json.encode(body)));
|
||||
if (response.statusCode == 400) {
|
||||
final decodedBody = json.decode(response.body) as Map<String, dynamic>;
|
||||
throw Exception(decodedBody['message'] as String);
|
||||
|
||||
@@ -5,15 +5,24 @@ class CWBitcoin extends Bitcoin {
|
||||
TransactionPriority getMediumTransactionPriority() => BitcoinTransactionPriority.medium;
|
||||
|
||||
@override
|
||||
WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({String name, String mnemonic, String password})
|
||||
WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({
|
||||
required String name,
|
||||
required String mnemonic,
|
||||
required String password})
|
||||
=> BitcoinRestoreWalletFromSeedCredentials(name: name, mnemonic: mnemonic, password: password);
|
||||
|
||||
@override
|
||||
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({String name, String password, String wif, WalletInfo walletInfo})
|
||||
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({
|
||||
required String name,
|
||||
required String password,
|
||||
required String wif,
|
||||
WalletInfo? walletInfo})
|
||||
=> BitcoinRestoreWalletFromWIFCredentials(name: name, password: password, wif: wif, walletInfo: walletInfo);
|
||||
|
||||
@override
|
||||
WalletCredentials createBitcoinNewWalletCredentials({String name, WalletInfo walletInfo})
|
||||
WalletCredentials createBitcoinNewWalletCredentials({
|
||||
required String name,
|
||||
WalletInfo? walletInfo})
|
||||
=> BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo);
|
||||
|
||||
@override
|
||||
@@ -55,7 +64,7 @@ class CWBitcoin extends Bitcoin {
|
||||
}
|
||||
|
||||
@override
|
||||
Object createBitcoinTransactionCredentials(List<Output> outputs, {TransactionPriority priority, int feeRate})
|
||||
Object createBitcoinTransactionCredentials(List<Output> outputs, {required TransactionPriority priority, int? feeRate})
|
||||
=> BitcoinTransactionCredentials(
|
||||
outputs.map((out) => OutputInfo(
|
||||
fiatAmount: out.fiatAmount,
|
||||
@@ -71,7 +80,7 @@ class CWBitcoin extends Bitcoin {
|
||||
feeRate: feeRate);
|
||||
|
||||
@override
|
||||
Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs, {TransactionPriority priority, int feeRate})
|
||||
Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs, {TransactionPriority? priority, required int feeRate})
|
||||
=> BitcoinTransactionCredentials(
|
||||
outputs,
|
||||
priority: priority != null ? priority as BitcoinTransactionPriority : null,
|
||||
@@ -92,17 +101,21 @@ class CWBitcoin extends Bitcoin {
|
||||
}
|
||||
|
||||
@override
|
||||
String formatterBitcoinAmountToString({int amount})
|
||||
String formatterBitcoinAmountToString({required int amount})
|
||||
=> bitcoinAmountToString(amount: amount);
|
||||
|
||||
@override
|
||||
double formatterBitcoinAmountToDouble({int amount})
|
||||
double formatterBitcoinAmountToDouble({required int amount})
|
||||
=> bitcoinAmountToDouble(amount: amount);
|
||||
|
||||
@override
|
||||
int formatterStringDoubleToBitcoinAmount(String amount)
|
||||
=> stringDoubleToBitcoinAmount(amount);
|
||||
|
||||
@override
|
||||
String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate)
|
||||
=> (priority as BitcoinTransactionPriority).labelWithRate(rate);
|
||||
|
||||
@override
|
||||
List<Unspent> getUnspents(Object wallet) {
|
||||
final bitcoinWallet = wallet as ElectrumWallet;
|
||||
@@ -127,4 +140,20 @@ class CWBitcoin extends Bitcoin {
|
||||
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
|
||||
return LitecoinWalletService(walletInfoSource, unspentCoinSource);
|
||||
}
|
||||
|
||||
@override
|
||||
TransactionPriority getBitcoinTransactionPriorityMedium()
|
||||
=> BitcoinTransactionPriority.medium;
|
||||
|
||||
@override
|
||||
TransactionPriority getLitecoinTransactionPriorityMedium()
|
||||
=> LitecoinTransactionPriority.medium;
|
||||
|
||||
@override
|
||||
TransactionPriority getBitcoinTransactionPrioritySlow()
|
||||
=> BitcoinTransactionPriority.slow;
|
||||
|
||||
@override
|
||||
TransactionPriority getLitecoinTransactionPrioritySlow()
|
||||
=> LitecoinTransactionPriority.slow;
|
||||
}
|
||||
@@ -2,13 +2,13 @@ import 'package:flutter/foundation.dart';
|
||||
|
||||
class BuyAmount {
|
||||
BuyAmount({
|
||||
@required this.sourceAmount,
|
||||
@required this.destAmount,
|
||||
required this.sourceAmount,
|
||||
required this.destAmount,
|
||||
this.achSourceAmount,
|
||||
this.minAmount = 0});
|
||||
|
||||
final double sourceAmount;
|
||||
final double destAmount;
|
||||
final double achSourceAmount;
|
||||
final double? achSourceAmount;
|
||||
final int minAmount;
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider_description.dart';
|
||||
|
||||
class BuyException implements Exception {
|
||||
BuyException({@required this.description, @required this.text});
|
||||
BuyException({required this.description, required this.text});
|
||||
|
||||
final BuyProviderDescription description;
|
||||
final String text;
|
||||
|
||||
@@ -5,7 +5,7 @@ import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
abstract class BuyProvider {
|
||||
BuyProvider({this.wallet, this.isTestEnvironment});
|
||||
BuyProvider({required this.wallet, required this.isTestEnvironment});
|
||||
|
||||
final WalletBase wallet;
|
||||
final bool isTestEnvironment;
|
||||
|
||||
@@ -2,20 +2,20 @@ import 'package:cw_core/enumerable_item.dart';
|
||||
|
||||
class BuyProviderDescription extends EnumerableItem<int>
|
||||
with Serializable<int> {
|
||||
const BuyProviderDescription({String title, int raw})
|
||||
const BuyProviderDescription({required String title, required int raw})
|
||||
: super(title: title, raw: raw);
|
||||
|
||||
static const wyre = BuyProviderDescription(title: 'Wyre', raw: 0);
|
||||
static const moonPay = BuyProviderDescription(title: 'MoonPay', raw: 1);
|
||||
|
||||
static BuyProviderDescription deserialize({int raw}) {
|
||||
static BuyProviderDescription deserialize({required int raw}) {
|
||||
switch (raw) {
|
||||
case 0:
|
||||
return wyre;
|
||||
case 1:
|
||||
return moonPay;
|
||||
default:
|
||||
return null;
|
||||
throw Exception('Incorrect token $raw for BuyProviderDescription deserialize');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider_description.dart';
|
||||
|
||||
Image getBuyProviderIcon(BuyProviderDescription providerDescription,
|
||||
Image? getBuyProviderIcon(BuyProviderDescription providerDescription,
|
||||
{Color iconColor = Colors.black}) {
|
||||
|
||||
final _wyreIcon =
|
||||
|
||||
@@ -23,7 +23,7 @@ class MoonPaySellProvider {
|
||||
final bool isTest;
|
||||
final String baseUrl;
|
||||
|
||||
Future<String> requestUrl({CryptoCurrency currency, String refundWalletAddress}) async {
|
||||
Future<String> requestUrl({required CryptoCurrency currency, required String refundWalletAddress}) async {
|
||||
final originalUri = Uri.https(
|
||||
baseUrl, '', <String, dynamic>{
|
||||
'apiKey': _apiKey,
|
||||
@@ -48,10 +48,9 @@ class MoonPaySellProvider {
|
||||
}
|
||||
|
||||
class MoonPayBuyProvider extends BuyProvider {
|
||||
MoonPayBuyProvider({WalletBase wallet, bool isTestEnvironment = false})
|
||||
: super(wallet: wallet, isTestEnvironment: isTestEnvironment) {
|
||||
baseUrl = isTestEnvironment ? _baseTestUrl : _baseProductUrl;
|
||||
}
|
||||
MoonPayBuyProvider({required WalletBase wallet, bool isTestEnvironment = false})
|
||||
: baseUrl = isTestEnvironment ? _baseTestUrl : _baseProductUrl,
|
||||
super(wallet: wallet, isTestEnvironment: isTestEnvironment);
|
||||
|
||||
static const _baseTestUrl = 'https://buy-staging.moonpay.com';
|
||||
static const _baseProductUrl = 'https://buy.moonpay.com';
|
||||
@@ -109,8 +108,8 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||
_quoteSuffix + '/?apiKey=' + _apiKey +
|
||||
'&baseCurrencyAmount=' + amount +
|
||||
'&baseCurrencyCode=' + sourceCurrency.toLowerCase();
|
||||
|
||||
final response = await get(url);
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw BuyException(
|
||||
@@ -133,8 +132,8 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||
Future<Order> findOrderById(String id) async {
|
||||
final url = _apiUrl + _transactionsSuffix + '/$id' +
|
||||
'?apiKey=' + _apiKey;
|
||||
|
||||
final response = await get(url);
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw BuyException(
|
||||
@@ -164,8 +163,8 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||
static Future<bool> onEnabled() async {
|
||||
final url = _apiUrl + _ipAddressSuffix + '?apiKey=' + _apiKey;
|
||||
var isBuyEnable = false;
|
||||
|
||||
final response = await get(url);
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
|
||||
try {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
+27
-22
@@ -8,54 +8,59 @@ part 'order.g.dart';
|
||||
@HiveType(typeId: Order.typeId)
|
||||
class Order extends HiveObject {
|
||||
Order(
|
||||
{this.id,
|
||||
BuyProviderDescription provider,
|
||||
this.transferId,
|
||||
{required this.id,
|
||||
required this.transferId,
|
||||
required this.createdAt,
|
||||
required this.amount,
|
||||
required this.receiveAddress,
|
||||
required this.walletId,
|
||||
BuyProviderDescription? provider,
|
||||
TradeState? state,
|
||||
this.from,
|
||||
this.to,
|
||||
TradeState state,
|
||||
this.createdAt,
|
||||
this.amount,
|
||||
this.receiveAddress,
|
||||
this.walletId})
|
||||
: providerRaw = provider?.raw,
|
||||
stateRaw = state?.raw;
|
||||
this.to}) {
|
||||
if (provider != null) {
|
||||
providerRaw = provider.raw;
|
||||
}
|
||||
if (state != null) {
|
||||
stateRaw = state.raw;
|
||||
}
|
||||
}
|
||||
|
||||
static const typeId = 8;
|
||||
static const boxName = 'Orders';
|
||||
static const boxKey = 'ordersBoxKey';
|
||||
|
||||
@HiveField(0)
|
||||
@HiveField(0, defaultValue: '')
|
||||
String id;
|
||||
|
||||
@HiveField(1)
|
||||
@HiveField(1, defaultValue: '')
|
||||
String transferId;
|
||||
|
||||
@HiveField(2)
|
||||
String from;
|
||||
String? from;
|
||||
|
||||
@HiveField(3)
|
||||
String to;
|
||||
String? to;
|
||||
|
||||
@HiveField(4)
|
||||
String stateRaw;
|
||||
@HiveField(4, defaultValue: '')
|
||||
late String stateRaw;
|
||||
|
||||
TradeState get state => TradeState.deserialize(raw: stateRaw);
|
||||
|
||||
@HiveField(5)
|
||||
DateTime createdAt;
|
||||
|
||||
@HiveField(6)
|
||||
@HiveField(6, defaultValue: '')
|
||||
String amount;
|
||||
|
||||
@HiveField(7)
|
||||
@HiveField(7, defaultValue: '')
|
||||
String receiveAddress;
|
||||
|
||||
@HiveField(8)
|
||||
@HiveField(8, defaultValue: '')
|
||||
String walletId;
|
||||
|
||||
@HiveField(9)
|
||||
int providerRaw;
|
||||
@HiveField(9, defaultValue: 0)
|
||||
late int providerRaw;
|
||||
|
||||
BuyProviderDescription get provider =>
|
||||
BuyProviderDescription.deserialize(raw: providerRaw);
|
||||
|
||||
@@ -11,12 +11,11 @@ import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
|
||||
class WyreBuyProvider extends BuyProvider {
|
||||
WyreBuyProvider({WalletBase wallet, bool isTestEnvironment = false})
|
||||
: super(wallet: wallet, isTestEnvironment: isTestEnvironment) {
|
||||
baseApiUrl = isTestEnvironment
|
||||
WyreBuyProvider({required WalletBase wallet, bool isTestEnvironment = false})
|
||||
: baseApiUrl = isTestEnvironment
|
||||
? _baseTestApiUrl
|
||||
: _baseProductApiUrl;
|
||||
}
|
||||
: _baseProductApiUrl,
|
||||
super(wallet: wallet, isTestEnvironment: isTestEnvironment);
|
||||
|
||||
static const _baseTestApiUrl = 'https://api.testwyre.com';
|
||||
static const _baseProductApiUrl = 'https://api.sendwyre.com';
|
||||
@@ -50,6 +49,7 @@ class WyreBuyProvider extends BuyProvider {
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
final url = baseApiUrl + _ordersSuffix + _reserveSuffix +
|
||||
_timeStampSuffix + timestamp;
|
||||
final uri = Uri.parse(url);
|
||||
final body = {
|
||||
'amount': amount,
|
||||
'sourceCurrency': sourceCurrency,
|
||||
@@ -58,8 +58,7 @@ class WyreBuyProvider extends BuyProvider {
|
||||
'referrerAccountId': _accountId,
|
||||
'lockFields': ['amount', 'sourceCurrency', 'destCurrency', 'dest']
|
||||
};
|
||||
|
||||
final response = await post(url,
|
||||
final response = await post(uri,
|
||||
headers: {
|
||||
'Authorization': 'Bearer $_secretKey',
|
||||
'Content-Type': 'application/json',
|
||||
@@ -89,8 +88,8 @@ class WyreBuyProvider extends BuyProvider {
|
||||
'accountId': _accountId,
|
||||
'country': _countryCode
|
||||
};
|
||||
|
||||
final response = await post(quoteUrl,
|
||||
final uri = Uri.parse(quoteUrl);
|
||||
final response = await post(uri,
|
||||
headers: {
|
||||
'Authorization': 'Bearer $_secretKey',
|
||||
'Content-Type': 'application/json',
|
||||
@@ -115,7 +114,8 @@ class WyreBuyProvider extends BuyProvider {
|
||||
@override
|
||||
Future<Order> findOrderById(String id) async {
|
||||
final orderUrl = baseApiUrl + _ordersSuffix + '/$id';
|
||||
final orderResponse = await get(orderUrl);
|
||||
final orderUri = Uri.parse(orderUrl);
|
||||
final orderResponse = await get(orderUri);
|
||||
|
||||
if (orderResponse.statusCode != 200) {
|
||||
throw BuyException(
|
||||
@@ -136,7 +136,8 @@ class WyreBuyProvider extends BuyProvider {
|
||||
|
||||
final transferUrl =
|
||||
baseApiUrl + _transferSuffix + transferId + _trackSuffix;
|
||||
final transferResponse = await get(transferUrl);
|
||||
final transferUri = Uri.parse(transferUrl);
|
||||
final transferResponse = await get(transferUri);
|
||||
|
||||
if (transferResponse.statusCode != 200) {
|
||||
throw BuyException(
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
class AddressLabelValidator extends TextValidator {
|
||||
AddressLabelValidator({WalletType type})
|
||||
AddressLabelValidator({WalletType? type})
|
||||
: super(
|
||||
errorMessage: S.current.error_text_subaddress_name,
|
||||
pattern: '''^[^`,'"]{1,20}\$''',
|
||||
|
||||
+106
-26
@@ -4,7 +4,7 @@ import 'package:cake_wallet/core/validator.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class AddressValidator extends TextValidator {
|
||||
AddressValidator({@required CryptoCurrency type})
|
||||
AddressValidator({required CryptoCurrency type})
|
||||
: super(
|
||||
errorMessage: S.current.error_text_address,
|
||||
pattern: getPattern(type),
|
||||
@@ -13,37 +13,29 @@ class AddressValidator extends TextValidator {
|
||||
static String getPattern(CryptoCurrency type) {
|
||||
switch (type) {
|
||||
case CryptoCurrency.xmr:
|
||||
return '[0-9a-zA-Z]';
|
||||
return '^4[0-9a-zA-Z]{94}\$|^8[0-9a-zA-Z]{94}\$|^[0-9a-zA-Z]{106}\$';
|
||||
case CryptoCurrency.ada:
|
||||
return '^[0-9a-zA-Z]{59}\$|^[0-9a-zA-Z]{92}\$|^[0-9a-zA-Z]{104}\$'
|
||||
'|^[0-9a-zA-Z]{105}\$|^addr1[0-9a-zA-Z]{98}\$';
|
||||
case CryptoCurrency.bch:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.bnb:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.btc:
|
||||
return '^1[0-9a-zA-Z]{32}\$|^1[0-9a-zA-Z]{33}\$|^3[0-9a-zA-Z]{32}\$'
|
||||
'|^3[0-9a-zA-Z]{33}\$|^bc1[0-9a-zA-Z]{39}\$|^bc1[0-9a-zA-Z]{59}\$';
|
||||
case CryptoCurrency.dai:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.dash:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.eos:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.eth:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.ltc:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.nano:
|
||||
return '[0-9a-zA-Z_]';
|
||||
case CryptoCurrency.trx:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.usdt:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.usdterc20:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.xlm:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.usdc:
|
||||
case CryptoCurrency.usdcpoly:
|
||||
case CryptoCurrency.husd:
|
||||
case CryptoCurrency.ape:
|
||||
case CryptoCurrency.avaxc:
|
||||
case CryptoCurrency.eth:
|
||||
case CryptoCurrency.mana:
|
||||
case CryptoCurrency.matic:
|
||||
case CryptoCurrency.maticpoly:
|
||||
case CryptoCurrency.mkr:
|
||||
case CryptoCurrency.oxt:
|
||||
case CryptoCurrency.paxg:
|
||||
case CryptoCurrency.uni:
|
||||
return '0x[0-9a-zA-Z]';
|
||||
case CryptoCurrency.xrp:
|
||||
return '^[0-9a-zA-Z]{34}\$|^X[0-9a-zA-Z]{46}\$';
|
||||
case CryptoCurrency.xhv:
|
||||
@@ -61,18 +53,54 @@ class AddressValidator extends TextValidator {
|
||||
case CryptoCurrency.xnok:
|
||||
case CryptoCurrency.xnzd:
|
||||
case CryptoCurrency.xusd:
|
||||
case CryptoCurrency.usdt:
|
||||
case CryptoCurrency.usdterc20:
|
||||
case CryptoCurrency.xlm:
|
||||
case CryptoCurrency.trx:
|
||||
case CryptoCurrency.dai:
|
||||
case CryptoCurrency.dash:
|
||||
case CryptoCurrency.eos:
|
||||
case CryptoCurrency.ltc:
|
||||
case CryptoCurrency.bch:
|
||||
case CryptoCurrency.bnb:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.hbar:
|
||||
return '[0-9a-zA-Z.]';
|
||||
case CryptoCurrency.zaddr:
|
||||
return '^zs[0-9a-zA-Z]{75}';
|
||||
case CryptoCurrency.zec:
|
||||
return '^t1[0-9a-zA-Z]{33}\$|^t3[0-9a-zA-Z]{33}\$';
|
||||
case CryptoCurrency.dcr:
|
||||
return 'D[ksecS]([0-9a-zA-Z])+';
|
||||
case CryptoCurrency.rvn:
|
||||
return '[Rr]([1-9a-km-zA-HJ-NP-Z]){33}';
|
||||
case CryptoCurrency.near:
|
||||
return '[0-9a-f]{64}';
|
||||
case CryptoCurrency.rune:
|
||||
return 'thor1[0-9a-z]{38}';
|
||||
case CryptoCurrency.scrt:
|
||||
return 'secret1[0-9a-z]{38}';
|
||||
case CryptoCurrency.stx:
|
||||
return 'S[MP][0-9a-zA-Z]+';
|
||||
case CryptoCurrency.kmd:
|
||||
return 'R[0-9a-zA-Z]{33}';
|
||||
case CryptoCurrency.pivx:
|
||||
return 'D([1-9a-km-zA-HJ-NP-Z]){33}';
|
||||
default:
|
||||
return '[0-9a-zA-Z]';
|
||||
}
|
||||
}
|
||||
|
||||
static List<int> getLength(CryptoCurrency type) {
|
||||
static List<int>? getLength(CryptoCurrency type) {
|
||||
switch (type) {
|
||||
case CryptoCurrency.xmr:
|
||||
return [95, 106];
|
||||
return null;
|
||||
case CryptoCurrency.ada:
|
||||
return null;
|
||||
case CryptoCurrency.ape:
|
||||
return [42];
|
||||
case CryptoCurrency.avaxc:
|
||||
return [42];
|
||||
case CryptoCurrency.bch:
|
||||
return [42];
|
||||
case CryptoCurrency.bnb:
|
||||
@@ -91,12 +119,22 @@ class AddressValidator extends TextValidator {
|
||||
return [34, 43];
|
||||
case CryptoCurrency.nano:
|
||||
return [64, 65];
|
||||
case CryptoCurrency.sc:
|
||||
return [76];
|
||||
case CryptoCurrency.sol:
|
||||
return [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44];
|
||||
case CryptoCurrency.trx:
|
||||
return [34];
|
||||
case CryptoCurrency.usdc:
|
||||
return [42];
|
||||
case CryptoCurrency.usdcsol:
|
||||
return [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44];
|
||||
case CryptoCurrency.usdt:
|
||||
return [34];
|
||||
case CryptoCurrency.usdterc20:
|
||||
return [42];
|
||||
case CryptoCurrency.usdttrc20:
|
||||
return [34];
|
||||
case CryptoCurrency.xlm:
|
||||
return [56];
|
||||
case CryptoCurrency.xrp:
|
||||
@@ -116,6 +154,48 @@ class AddressValidator extends TextValidator {
|
||||
case CryptoCurrency.xnzd:
|
||||
case CryptoCurrency.xusd:
|
||||
return [98, 99, 106];
|
||||
case CryptoCurrency.btt:
|
||||
return [34];
|
||||
case CryptoCurrency.bttbsc:
|
||||
return [34];
|
||||
case CryptoCurrency.doge:
|
||||
return [34];
|
||||
case CryptoCurrency.firo:
|
||||
return [34];
|
||||
case CryptoCurrency.hbar:
|
||||
return [4, 5, 6, 7, 8, 9, 10, 11];
|
||||
case CryptoCurrency.xvg:
|
||||
return [34];
|
||||
case CryptoCurrency.zen:
|
||||
return [35];
|
||||
case CryptoCurrency.zaddr:
|
||||
return null;
|
||||
case CryptoCurrency.zec:
|
||||
return null;
|
||||
case CryptoCurrency.kmd:
|
||||
case CryptoCurrency.pivx:
|
||||
case CryptoCurrency.rvn:
|
||||
return [34];
|
||||
case CryptoCurrency.dcr:
|
||||
return [35];
|
||||
case CryptoCurrency.stx:
|
||||
return [40, 41, 42];
|
||||
case CryptoCurrency.usdcpoly:
|
||||
case CryptoCurrency.husd:
|
||||
case CryptoCurrency.mana:
|
||||
case CryptoCurrency.matic:
|
||||
case CryptoCurrency.maticpoly:
|
||||
case CryptoCurrency.mkr:
|
||||
case CryptoCurrency.oxt:
|
||||
case CryptoCurrency.paxg:
|
||||
case CryptoCurrency.uni:
|
||||
return [42];
|
||||
case CryptoCurrency.rune:
|
||||
return [43];
|
||||
case CryptoCurrency.scrt:
|
||||
return [45];
|
||||
case CryptoCurrency.near:
|
||||
return [64];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
|
||||
+27
-27
@@ -1,37 +1,37 @@
|
||||
abstract class Amount {
|
||||
Amount(this.value);
|
||||
// abstract class Amount {
|
||||
// Amount(this.value);
|
||||
|
||||
int value;
|
||||
// int value;
|
||||
|
||||
int minorDigits;
|
||||
// int minorDigits;
|
||||
|
||||
String code;
|
||||
// String code;
|
||||
|
||||
String formatted();
|
||||
}
|
||||
// String formatted();
|
||||
// }
|
||||
|
||||
class MoneroAmount extends Amount {
|
||||
MoneroAmount(int value) : super(value) {
|
||||
minorDigits = 12;
|
||||
code = 'XMR';
|
||||
}
|
||||
// class MoneroAmount extends Amount {
|
||||
// MoneroAmount(int value) : super(value) {
|
||||
// minorDigits = 12;
|
||||
// code = 'XMR';
|
||||
// }
|
||||
|
||||
// const moneroAmountLength = 12;
|
||||
// const moneroAmountDivider = 1000000000000;
|
||||
// final moneroAmountFormat = NumberFormat()
|
||||
// ..maximumFractionDigits = moneroAmountLength
|
||||
// ..minimumFractionDigits = 1;
|
||||
// // const moneroAmountLength = 12;
|
||||
// // const moneroAmountDivider = 1000000000000;
|
||||
// // final moneroAmountFormat = NumberFormat()
|
||||
// // ..maximumFractionDigits = moneroAmountLength
|
||||
// // ..minimumFractionDigits = 1;
|
||||
|
||||
// String moneroAmountToString({int amount}) =>
|
||||
// moneroAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider));
|
||||
// // String moneroAmountToString({int amount}) =>
|
||||
// // moneroAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider));
|
||||
|
||||
// double moneroAmountToDouble({int amount}) => cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider);
|
||||
// // double moneroAmountToDouble({int amount}) => cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider);
|
||||
|
||||
// int moneroParseAmount({String amount}) => moneroAmountFormat.parse(amount).toInt();
|
||||
// // int moneroParseAmount({String amount}) => moneroAmountFormat.parse(amount).toInt();
|
||||
|
||||
@override
|
||||
String formatted() {
|
||||
// TODO: implement formatted
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
// @override
|
||||
// String formatted() {
|
||||
// // TODO: implement formatted
|
||||
// throw UnimplementedError();
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class AmountConverter {
|
||||
static const _moneroAmountLength = 12;
|
||||
static const _moneroAmountDivider = 1000000000000;
|
||||
static const _litecoinAmountDivider = 100000000;
|
||||
static const _ethereumAmountDivider = 1000000000000000000;
|
||||
static const _dashAmountDivider = 100000000;
|
||||
static const _bitcoinCashAmountDivider = 100000000;
|
||||
static const _bitcoinAmountDivider = 100000000;
|
||||
static const _bitcoinAmountLength = 8;
|
||||
static final _bitcoinAmountFormat = NumberFormat()
|
||||
..maximumFractionDigits = _bitcoinAmountLength
|
||||
..minimumFractionDigits = 1;
|
||||
static final _moneroAmountFormat = NumberFormat()
|
||||
..maximumFractionDigits = _moneroAmountLength
|
||||
..minimumFractionDigits = 1;
|
||||
|
||||
static double amountIntToDouble(CryptoCurrency cryptoCurrency, int amount) {
|
||||
switch (cryptoCurrency) {
|
||||
case CryptoCurrency.xmr:
|
||||
return _moneroAmountToDouble(amount);
|
||||
case CryptoCurrency.btc:
|
||||
return _bitcoinAmountToDouble(amount);
|
||||
case CryptoCurrency.bch:
|
||||
return _bitcoinCashAmountToDouble(amount);
|
||||
case CryptoCurrency.dash:
|
||||
return _dashAmountToDouble(amount);
|
||||
case CryptoCurrency.eth:
|
||||
return _ethereumAmountToDouble(amount);
|
||||
case CryptoCurrency.ltc:
|
||||
return _litecoinAmountToDouble(amount);
|
||||
case CryptoCurrency.xhv:
|
||||
case CryptoCurrency.xag:
|
||||
case CryptoCurrency.xau:
|
||||
case CryptoCurrency.xaud:
|
||||
case CryptoCurrency.xbtc:
|
||||
case CryptoCurrency.xcad:
|
||||
case CryptoCurrency.xchf:
|
||||
case CryptoCurrency.xcny:
|
||||
case CryptoCurrency.xeur:
|
||||
case CryptoCurrency.xgbp:
|
||||
case CryptoCurrency.xjpy:
|
||||
case CryptoCurrency.xnok:
|
||||
case CryptoCurrency.xnzd:
|
||||
case CryptoCurrency.xusd:
|
||||
return _moneroAmountToDouble(amount);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static int amountStringToInt(CryptoCurrency cryptoCurrency, String amount) {
|
||||
switch (cryptoCurrency) {
|
||||
case CryptoCurrency.xmr:
|
||||
return _moneroParseAmount(amount);
|
||||
case CryptoCurrency.xhv:
|
||||
case CryptoCurrency.xag:
|
||||
case CryptoCurrency.xau:
|
||||
case CryptoCurrency.xaud:
|
||||
case CryptoCurrency.xbtc:
|
||||
case CryptoCurrency.xcad:
|
||||
case CryptoCurrency.xchf:
|
||||
case CryptoCurrency.xcny:
|
||||
case CryptoCurrency.xeur:
|
||||
case CryptoCurrency.xgbp:
|
||||
case CryptoCurrency.xjpy:
|
||||
case CryptoCurrency.xnok:
|
||||
case CryptoCurrency.xnzd:
|
||||
case CryptoCurrency.xusd:
|
||||
return _moneroParseAmount(amount);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static String amountIntToString(CryptoCurrency cryptoCurrency, int amount) {
|
||||
switch (cryptoCurrency) {
|
||||
case CryptoCurrency.xmr:
|
||||
return _moneroAmountToString(amount);
|
||||
case CryptoCurrency.btc:
|
||||
return _bitcoinAmountToString(amount);
|
||||
case CryptoCurrency.xhv:
|
||||
case CryptoCurrency.xag:
|
||||
case CryptoCurrency.xau:
|
||||
case CryptoCurrency.xaud:
|
||||
case CryptoCurrency.xbtc:
|
||||
case CryptoCurrency.xcad:
|
||||
case CryptoCurrency.xchf:
|
||||
case CryptoCurrency.xcny:
|
||||
case CryptoCurrency.xeur:
|
||||
case CryptoCurrency.xgbp:
|
||||
case CryptoCurrency.xjpy:
|
||||
case CryptoCurrency.xnok:
|
||||
case CryptoCurrency.xnzd:
|
||||
case CryptoCurrency.xusd:
|
||||
return _moneroAmountToString(amount);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static double cryptoAmountToDouble({num amount, num divider}) =>
|
||||
amount / divider;
|
||||
|
||||
static String _moneroAmountToString(int amount) => _moneroAmountFormat.format(
|
||||
cryptoAmountToDouble(amount: amount, divider: _moneroAmountDivider));
|
||||
|
||||
static double _moneroAmountToDouble(int amount) =>
|
||||
cryptoAmountToDouble(amount: amount, divider: _moneroAmountDivider);
|
||||
|
||||
static int _moneroParseAmount(String amount) =>
|
||||
_moneroAmountFormat.parse(amount).toInt();
|
||||
|
||||
static String _bitcoinAmountToString(int amount) =>
|
||||
_bitcoinAmountFormat.format(
|
||||
cryptoAmountToDouble(amount: amount, divider: _bitcoinAmountDivider));
|
||||
|
||||
static double _bitcoinAmountToDouble(int amount) =>
|
||||
cryptoAmountToDouble(amount: amount, divider: _bitcoinAmountDivider);
|
||||
|
||||
static int _doubleToBitcoinAmount(double amount) =>
|
||||
(amount * _bitcoinAmountDivider).toInt();
|
||||
|
||||
static double _bitcoinCashAmountToDouble(int amount) =>
|
||||
cryptoAmountToDouble(amount: amount, divider: _bitcoinCashAmountDivider);
|
||||
|
||||
static double _dashAmountToDouble(int amount) =>
|
||||
cryptoAmountToDouble(amount: amount, divider: _dashAmountDivider);
|
||||
|
||||
static double _ethereumAmountToDouble(num amount) =>
|
||||
cryptoAmountToDouble(amount: amount, divider: _ethereumAmountDivider);
|
||||
|
||||
static double _litecoinAmountToDouble(int amount) =>
|
||||
cryptoAmountToDouble(amount: amount, divider: _litecoinAmountDivider);
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
class AmountValidator extends TextValidator {
|
||||
AmountValidator({WalletType type, bool isAutovalidate = false})
|
||||
AmountValidator({required WalletType type, bool isAutovalidate = false})
|
||||
: super(
|
||||
errorMessage: S.current.error_text_amount,
|
||||
pattern: _pattern(type),
|
||||
|
||||
@@ -6,12 +6,12 @@ import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||
import 'package:cake_wallet/entities/encrypt.dart';
|
||||
|
||||
class AuthService with Store {
|
||||
AuthService({this.secureStorage, this.sharedPreferences});
|
||||
AuthService({required this.secureStorage, required this.sharedPreferences});
|
||||
|
||||
final FlutterSecureStorage secureStorage;
|
||||
final SharedPreferences sharedPreferences;
|
||||
|
||||
Future setPassword(String password) async {
|
||||
Future<void> setPassword(String password) async {
|
||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||
final encodedPassword = encodedPinCode(pin: password);
|
||||
await secureStorage.write(key: key, value: encodedPassword);
|
||||
@@ -24,7 +24,7 @@ class AuthService with Store {
|
||||
var password = '';
|
||||
|
||||
try {
|
||||
password = await secureStorage.read(key: key);
|
||||
password = await secureStorage.read(key: key) ?? '';
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
@@ -35,7 +35,7 @@ class AuthService with Store {
|
||||
Future<bool> authenticate(String pin) async {
|
||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||
final encodedPin = await secureStorage.read(key: key);
|
||||
final decodedPin = decodedPinCode(pin: encodedPin);
|
||||
final decodedPin = decodedPinCode(pin: encodedPin!);
|
||||
|
||||
return decodedPin == pin;
|
||||
}
|
||||
|
||||
@@ -7,13 +7,13 @@ class AuthenticationInProgress extends AuthState {}
|
||||
class AuthenticatedSuccessfully extends AuthState {}
|
||||
|
||||
class AuthenticationFailure extends AuthState {
|
||||
AuthenticationFailure({this.error});
|
||||
AuthenticationFailure({required this.error});
|
||||
|
||||
final String error;
|
||||
}
|
||||
|
||||
class AuthenticationBanned extends AuthState {
|
||||
AuthenticationBanned({this.error});
|
||||
AuthenticationBanned({required this.error});
|
||||
|
||||
final String error;
|
||||
}
|
||||
|
||||
+187
-66
@@ -16,15 +16,18 @@ import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/wallet_types.g.dart';
|
||||
import 'package:cake_backup/backup.dart' as cake_backup;
|
||||
|
||||
class BackupService {
|
||||
BackupService(this._flutterSecureStorage, this._walletInfoSource,
|
||||
this._keyService, this._sharedPreferences)
|
||||
: _cipher = chacha20Poly1305Aead;
|
||||
: _cipher = Cryptography.instance.chacha20Poly1305Aead(),
|
||||
_correctWallets = <WalletInfo>[];
|
||||
|
||||
static const currentVersion = _v1;
|
||||
static const currentVersion = _v2;
|
||||
|
||||
static const _v1 = 1;
|
||||
static const _v2 = 2;
|
||||
|
||||
final Cipher _cipher;
|
||||
final FlutterSecureStorage _flutterSecureStorage;
|
||||
@@ -36,13 +39,16 @@ class BackupService {
|
||||
Future<void> importBackup(Uint8List data, String password,
|
||||
{String nonce = secrets.backupSalt}) async {
|
||||
final version = getVersion(data);
|
||||
final backupBytes = data.toList()..removeAt(0);
|
||||
final backupData = Uint8List.fromList(backupBytes);
|
||||
|
||||
switch (version) {
|
||||
case _v1:
|
||||
final backupBytes = data.toList()..removeAt(0);
|
||||
final backupData = Uint8List.fromList(backupBytes);
|
||||
await _importBackupV1(backupData, password, nonce: nonce);
|
||||
break;
|
||||
case _v2:
|
||||
await _importBackupV2(data, password);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -53,20 +59,26 @@ class BackupService {
|
||||
switch (version) {
|
||||
case _v1:
|
||||
return await _exportBackupV1(password, nonce: nonce);
|
||||
case _v2:
|
||||
return await _exportBackupV2(password);
|
||||
default:
|
||||
return null;
|
||||
throw Exception('Incorrect version: $version for exportBackup');
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Use v2 instead')
|
||||
Future<Uint8List> _exportBackupV1(String password,
|
||||
{String nonce = secrets.backupSalt}) async {
|
||||
{String nonce = secrets.backupSalt}) async
|
||||
=> throw Exception('Deprecated. Export for backups v1 is deprecated. Please use export v2.');
|
||||
|
||||
Future<Uint8List> _exportBackupV2(String password) async {
|
||||
final zipEncoder = ZipFileEncoder();
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final now = DateTime.now();
|
||||
final tmpDir = Directory('${appDir.path}/~_BACKUP_TMP');
|
||||
final archivePath = '${tmpDir.path}/backup_${now.toString()}.zip';
|
||||
final fileEntities = appDir.listSync(recursive: false);
|
||||
final keychainDump = await _exportKeychainDump(password, nonce: nonce);
|
||||
final keychainDump = await _exportKeychainDumpV2(password);
|
||||
final preferencesDump = await _exportPreferencesJSON();
|
||||
final preferencesDumpFile = File('${tmpDir.path}/~_preferences_dump_TMP');
|
||||
final keychainDumpFile = File('${tmpDir.path}/~_keychain_dump_TMP');
|
||||
@@ -91,21 +103,19 @@ class BackupService {
|
||||
});
|
||||
await keychainDumpFile.writeAsBytes(keychainDump.toList());
|
||||
await preferencesDumpFile.writeAsString(preferencesDump);
|
||||
zipEncoder.addFile(preferencesDumpFile, '~_preferences_dump');
|
||||
zipEncoder.addFile(keychainDumpFile, '~_keychain_dump');
|
||||
await zipEncoder.addFile(preferencesDumpFile, '~_preferences_dump');
|
||||
await zipEncoder.addFile(keychainDumpFile, '~_keychain_dump');
|
||||
zipEncoder.close();
|
||||
|
||||
final content = File(archivePath).readAsBytesSync();
|
||||
tmpDir.deleteSync(recursive: true);
|
||||
final encryptedData = await _encrypt(content, password, nonce);
|
||||
|
||||
return setVersion(encryptedData, currentVersion);
|
||||
return await _encryptV2(content, password);
|
||||
}
|
||||
|
||||
Future<void> _importBackupV1(Uint8List data, String password,
|
||||
{@required String nonce}) async {
|
||||
{required String nonce}) async {
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final decryptedData = await _decrypt(data, password, nonce);
|
||||
final decryptedData = await _decryptV1(data, password, nonce);
|
||||
final zip = ZipDecoder().decodeBytes(decryptedData);
|
||||
|
||||
zip.files.forEach((file) {
|
||||
@@ -122,7 +132,30 @@ class BackupService {
|
||||
});
|
||||
|
||||
await _verifyWallets();
|
||||
await _importKeychainDump(password, nonce: nonce);
|
||||
await _importKeychainDumpV1(password, nonce: nonce);
|
||||
await _importPreferencesDump();
|
||||
}
|
||||
|
||||
Future<void> _importBackupV2(Uint8List data, String password) async {
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final decryptedData = await _decryptV2(data, password);
|
||||
final zip = ZipDecoder().decodeBytes(decryptedData);
|
||||
|
||||
zip.files.forEach((file) {
|
||||
final filename = file.name;
|
||||
|
||||
if (file.isFile) {
|
||||
final content = file.content as List<int>;
|
||||
File('${appDir.path}/' + filename)
|
||||
..createSync(recursive: true)
|
||||
..writeAsBytesSync(content);
|
||||
} else {
|
||||
Directory('${appDir.path}/' + filename)..create(recursive: true);
|
||||
}
|
||||
});
|
||||
|
||||
await _verifyWallets();
|
||||
await _importKeychainDumpV2(password);
|
||||
await _importPreferencesDump();
|
||||
}
|
||||
|
||||
@@ -159,7 +192,7 @@ class BackupService {
|
||||
}
|
||||
|
||||
final data =
|
||||
json.decode(preferencesFile.readAsStringSync()) as Map<String, Object>;
|
||||
json.decode(preferencesFile.readAsStringSync()) as Map<String, dynamic>;
|
||||
String currentWalletName = data[PreferencesKey.currentWalletName] as String;
|
||||
int currentWalletType = data[PreferencesKey.currentWalletType] as int;
|
||||
|
||||
@@ -172,53 +205,97 @@ class BackupService {
|
||||
currentWalletType = serializeToInt(_correctWallets.first.type);
|
||||
}
|
||||
|
||||
final currentNodeId = data[PreferencesKey.currentNodeIdKey] as int?;
|
||||
final currentBalanceDisplayMode = data[PreferencesKey.currentBalanceDisplayModeKey] as int?;
|
||||
final currentFiatCurrency = data[PreferencesKey.currentFiatCurrencyKey] as String?;
|
||||
final shouldSaveRecipientAddress = data[PreferencesKey.shouldSaveRecipientAddressKey] as bool?;
|
||||
final currentTransactionPriorityKeyLegacy = data[PreferencesKey.currentTransactionPriorityKeyLegacy] as int?;
|
||||
final allowBiometricalAuthentication = data[PreferencesKey.allowBiometricalAuthenticationKey] as bool?;
|
||||
final currentBitcoinElectrumSererId = data[PreferencesKey.currentBitcoinElectrumSererIdKey] as int?;
|
||||
final currentLanguageCode = data[PreferencesKey.currentLanguageCode] as String?;
|
||||
final displayActionListMode = data[PreferencesKey.displayActionListModeKey] as int?;
|
||||
final currentPinLength = data[PreferencesKey.currentPinLength] as int?;
|
||||
final currentTheme = data[PreferencesKey.currentTheme] as int?;
|
||||
final currentDefaultSettingsMigrationVersion = data[PreferencesKey.currentDefaultSettingsMigrationVersion] as int?;
|
||||
final moneroTransactionPriority = data[PreferencesKey.moneroTransactionPriority] as int?;
|
||||
final bitcoinTransactionPriority = data[PreferencesKey.bitcoinTransactionPriority] as int?;
|
||||
|
||||
await _sharedPreferences.setString(PreferencesKey.currentWalletName,
|
||||
currentWalletName);
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentNodeIdKey,
|
||||
data[PreferencesKey.currentNodeIdKey] as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentBalanceDisplayModeKey,
|
||||
data[PreferencesKey.currentBalanceDisplayModeKey] as int);
|
||||
|
||||
if (currentNodeId != null)
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentNodeIdKey,
|
||||
currentNodeId);
|
||||
|
||||
if (currentBalanceDisplayMode != null)
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentBalanceDisplayModeKey,
|
||||
currentBalanceDisplayMode);
|
||||
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentWalletType,
|
||||
currentWalletType);
|
||||
await _sharedPreferences.setString(PreferencesKey.currentFiatCurrencyKey,
|
||||
data[PreferencesKey.currentFiatCurrencyKey] as String);
|
||||
await _sharedPreferences.setBool(
|
||||
|
||||
if (currentFiatCurrency != null)
|
||||
await _sharedPreferences.setString(PreferencesKey.currentFiatCurrencyKey,
|
||||
currentFiatCurrency);
|
||||
|
||||
if (shouldSaveRecipientAddress != null)
|
||||
await _sharedPreferences.setBool(
|
||||
PreferencesKey.shouldSaveRecipientAddressKey,
|
||||
data[PreferencesKey.shouldSaveRecipientAddressKey] as bool);
|
||||
await _sharedPreferences.setInt(
|
||||
shouldSaveRecipientAddress);
|
||||
|
||||
if (currentTransactionPriorityKeyLegacy != null)
|
||||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentTransactionPriorityKeyLegacy,
|
||||
data[PreferencesKey.currentTransactionPriorityKeyLegacy] as int);
|
||||
await _sharedPreferences.setBool(
|
||||
currentTransactionPriorityKeyLegacy);
|
||||
|
||||
if (allowBiometricalAuthentication != null)
|
||||
await _sharedPreferences.setBool(
|
||||
PreferencesKey.allowBiometricalAuthenticationKey,
|
||||
data[PreferencesKey.allowBiometricalAuthenticationKey] as bool);
|
||||
await _sharedPreferences.setInt(
|
||||
allowBiometricalAuthentication);
|
||||
|
||||
if (currentBitcoinElectrumSererId != null)
|
||||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentBitcoinElectrumSererIdKey,
|
||||
data[PreferencesKey.currentBitcoinElectrumSererIdKey] as int);
|
||||
await _sharedPreferences.setString(PreferencesKey.currentLanguageCode,
|
||||
data[PreferencesKey.currentLanguageCode] as String);
|
||||
await _sharedPreferences.setInt(PreferencesKey.displayActionListModeKey,
|
||||
data[PreferencesKey.displayActionListModeKey] as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentPinLength,
|
||||
data[PreferencesKey.currentPinLength] as int);
|
||||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentTheme, data[PreferencesKey.currentTheme] as int);
|
||||
await _sharedPreferences.setInt(
|
||||
currentBitcoinElectrumSererId);
|
||||
|
||||
if (currentLanguageCode != null)
|
||||
await _sharedPreferences.setString(PreferencesKey.currentLanguageCode,
|
||||
currentLanguageCode);
|
||||
|
||||
if (displayActionListMode != null)
|
||||
await _sharedPreferences.setInt(PreferencesKey.displayActionListModeKey,
|
||||
displayActionListMode);
|
||||
|
||||
if (currentPinLength != null)
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentPinLength,
|
||||
currentPinLength);
|
||||
|
||||
if (currentTheme != null)
|
||||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentTheme, currentTheme);
|
||||
|
||||
if (currentDefaultSettingsMigrationVersion != null)
|
||||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentDefaultSettingsMigrationVersion,
|
||||
data[PreferencesKey.currentDefaultSettingsMigrationVersion] as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.moneroTransactionPriority,
|
||||
data[PreferencesKey.moneroTransactionPriority] as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.bitcoinTransactionPriority,
|
||||
data[PreferencesKey.bitcoinTransactionPriority] as int);
|
||||
currentDefaultSettingsMigrationVersion);
|
||||
|
||||
if (moneroTransactionPriority != null)
|
||||
await _sharedPreferences.setInt(PreferencesKey.moneroTransactionPriority,
|
||||
moneroTransactionPriority);
|
||||
|
||||
if (bitcoinTransactionPriority != null)
|
||||
await _sharedPreferences.setInt(PreferencesKey.bitcoinTransactionPriority,
|
||||
bitcoinTransactionPriority);
|
||||
|
||||
await preferencesFile.delete();
|
||||
}
|
||||
|
||||
Future<void> _importKeychainDump(String password,
|
||||
{@required String nonce,
|
||||
Future<void> _importKeychainDumpV1(String password,
|
||||
{required String nonce,
|
||||
String keychainSalt = secrets.backupKeychainSalt}) async {
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
|
||||
final decryptedKeychainDumpFileData = await _decrypt(
|
||||
final decryptedKeychainDumpFileData = await _decryptV1(
|
||||
keychainDumpFile.readAsBytesSync(), '$keychainSalt$password', nonce);
|
||||
final keychainJSON = json.decode(utf8.decode(decryptedKeychainDumpFileData))
|
||||
as Map<String, dynamic>;
|
||||
@@ -243,6 +320,35 @@ class BackupService {
|
||||
keychainDumpFile.deleteSync();
|
||||
}
|
||||
|
||||
Future<void> _importKeychainDumpV2(String password,
|
||||
{String keychainSalt = secrets.backupKeychainSalt}) async {
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
|
||||
final decryptedKeychainDumpFileData = await _decryptV2(
|
||||
keychainDumpFile.readAsBytesSync(), '$keychainSalt$password');
|
||||
final keychainJSON = json.decode(utf8.decode(decryptedKeychainDumpFileData))
|
||||
as Map<String, dynamic>;
|
||||
final keychainWalletsInfo = keychainJSON['wallets'] as List;
|
||||
final decodedPin = keychainJSON['pin'] as String;
|
||||
final pinCodeKey = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||
final backupPasswordKey =
|
||||
generateStoreKeyFor(key: SecretStoreKey.backupPassword);
|
||||
final backupPassword = keychainJSON[backupPasswordKey] as String;
|
||||
|
||||
await _flutterSecureStorage.write(
|
||||
key: backupPasswordKey, value: backupPassword);
|
||||
|
||||
keychainWalletsInfo.forEach((dynamic rawInfo) async {
|
||||
final info = rawInfo as Map<String, dynamic>;
|
||||
await importWalletKeychainInfo(info);
|
||||
});
|
||||
|
||||
await _flutterSecureStorage.write(
|
||||
key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
|
||||
|
||||
keychainDumpFile.deleteSync();
|
||||
}
|
||||
|
||||
Future<void> importWalletKeychainInfo(Map<String, dynamic> info) async {
|
||||
final name = info['name'] as String;
|
||||
final password = info['password'] as String;
|
||||
@@ -250,12 +356,17 @@ class BackupService {
|
||||
await _keyService.saveWalletPassword(walletName: name, password: password);
|
||||
}
|
||||
|
||||
Future<Uint8List> _exportKeychainDump(String password,
|
||||
{@required String nonce,
|
||||
String keychainSalt = secrets.backupKeychainSalt}) async {
|
||||
@Deprecated('Use v2 instead')
|
||||
Future<Uint8List> _exportKeychainDumpV1(String password,
|
||||
{required String nonce,
|
||||
String keychainSalt = secrets.backupKeychainSalt}) async
|
||||
=> throw Exception('Deprecated');
|
||||
|
||||
Future<Uint8List> _exportKeychainDumpV2(String password,
|
||||
{String keychainSalt = secrets.backupKeychainSalt}) async {
|
||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||
final encodedPin = await _flutterSecureStorage.read(key: key);
|
||||
final decodedPin = decodedPinCode(pin: encodedPin);
|
||||
final decodedPin = decodedPinCode(pin: encodedPin!);
|
||||
final wallets =
|
||||
await Future.wait(_walletInfoSource.values.map((walletInfo) async {
|
||||
return {
|
||||
@@ -274,14 +385,14 @@ class BackupService {
|
||||
'wallets': wallets,
|
||||
backupPasswordKey: backupPassword
|
||||
}));
|
||||
final encrypted = await _encrypt(
|
||||
Uint8List.fromList(data), '$keychainSalt$password', nonce);
|
||||
final encrypted = await _encryptV2(
|
||||
Uint8List.fromList(data), '$keychainSalt$password');
|
||||
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
Future<String> _exportPreferencesJSON() async {
|
||||
final preferences = <String, Object>{
|
||||
final preferences = <String, dynamic>{
|
||||
PreferencesKey.currentWalletName:
|
||||
_sharedPreferences.getString(PreferencesKey.currentWalletName),
|
||||
PreferencesKey.currentNodeIdKey:
|
||||
@@ -328,19 +439,29 @@ class BackupService {
|
||||
return Uint8List.fromList(bytes);
|
||||
}
|
||||
|
||||
Future<Uint8List> _encrypt(
|
||||
Uint8List data, String secretKeySource, String nonceBase64) async {
|
||||
final secretKeyHash = await sha256.hash(utf8.encode(secretKeySource));
|
||||
@Deprecated('Use v2 instead')
|
||||
Future<Uint8List> _encryptV1(
|
||||
Uint8List data, String secretKeySource, String nonceBase64) async
|
||||
=> throw Exception('Deprecated');
|
||||
|
||||
Future<Uint8List> _decryptV1(
|
||||
Uint8List data, String secretKeySource, String nonceBase64, {int macLength = 16}) async {
|
||||
final secretKeyHash = await Cryptography.instance.sha256().hash(utf8.encode(secretKeySource));
|
||||
final secretKey = SecretKey(secretKeyHash.bytes);
|
||||
final nonce = Nonce(base64.decode(nonceBase64));
|
||||
return await _cipher.encrypt(data, secretKey: secretKey, nonce: nonce);
|
||||
final nonce = base64.decode(nonceBase64).toList();
|
||||
final box = SecretBox(
|
||||
Uint8List.sublistView(data, 0, data.lengthInBytes - macLength).toList(),
|
||||
nonce: nonce,
|
||||
mac: Mac(Uint8List.sublistView(data, data.lengthInBytes - macLength)));
|
||||
final plainData = await _cipher.decrypt(box, secretKey: secretKey);
|
||||
return Uint8List.fromList(plainData);
|
||||
}
|
||||
|
||||
Future<Uint8List> _decrypt(
|
||||
Uint8List data, String secretKeySource, String nonceBase64) async {
|
||||
final secretKeyHash = await sha256.hash(utf8.encode(secretKeySource));
|
||||
final secretKey = SecretKey(secretKeyHash.bytes);
|
||||
final nonce = Nonce(base64.decode(nonceBase64));
|
||||
return await _cipher.decrypt(data, secretKey: secretKey, nonce: nonce);
|
||||
}
|
||||
Future<Uint8List> _encryptV2(
|
||||
Uint8List data, String passphrase) async
|
||||
=> cake_backup.encrypt(passphrase, data, version: _v2);
|
||||
|
||||
Future<Uint8List> _decryptV2(
|
||||
Uint8List data, String passphrase) async
|
||||
=> cake_backup.decrypt(passphrase, data);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
|
||||
final fiatStringified = fiat.toString();
|
||||
final uri = Uri.https(fiatApiAuthority, fiatApiPath,
|
||||
<String, String>{'convert': fiatStringified});
|
||||
final response = await get(uri.toString());
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return 0.0;
|
||||
|
||||
@@ -7,15 +7,14 @@ class KeyService {
|
||||
|
||||
final FlutterSecureStorage _secureStorage;
|
||||
|
||||
Future<String> getWalletPassword({String walletName}) async {
|
||||
Future<String> getWalletPassword({required String walletName}) async {
|
||||
final key = generateStoreKeyFor(
|
||||
key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
|
||||
final encodedPassword = await _secureStorage.read(key: key);
|
||||
|
||||
return decodeWalletPassword(password: encodedPassword);
|
||||
return decodeWalletPassword(password: encodedPassword!);
|
||||
}
|
||||
|
||||
Future<void> saveWalletPassword({String walletName, String password}) async {
|
||||
Future<void> saveWalletPassword({required String walletName, required String password}) async {
|
||||
final key = generateStoreKeyFor(
|
||||
key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
|
||||
final encodedPassword = encodeWalletPassword(password: password);
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:cake_wallet/core/validator.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class MoneroLabelValidator extends TextValidator {
|
||||
MoneroLabelValidator({@required CryptoCurrency type})
|
||||
MoneroLabelValidator()
|
||||
: super(
|
||||
errorMessage: S.current.error_text_account_name,
|
||||
pattern: '^[a-zA-Z0-9_ ]{1,15}\$',
|
||||
|
||||
@@ -7,23 +7,24 @@ import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/utils/language_list.dart';
|
||||
|
||||
class SeedValidator extends Validator<MnemonicItem> {
|
||||
SeedValidator({this.type, this.language})
|
||||
: _words = getWordList(type: type, language: language);
|
||||
SeedValidator({required this.type, required this.language})
|
||||
: _words = getWordList(type: type, language: language),
|
||||
super(errorMessage: 'Wrong seed mnemonic');
|
||||
|
||||
final WalletType type;
|
||||
final String language;
|
||||
final List<String> _words;
|
||||
|
||||
static List<String> getWordList({WalletType type, String language}) {
|
||||
static List<String> getWordList({required WalletType type, required String language}) {
|
||||
switch (type) {
|
||||
case WalletType.bitcoin:
|
||||
return getBitcoinWordList(language);
|
||||
case WalletType.litecoin:
|
||||
return getBitcoinWordList(language);
|
||||
case WalletType.monero:
|
||||
return monero.getMoneroWordList(language);
|
||||
return monero!.getMoneroWordList(language);
|
||||
case WalletType.haven:
|
||||
return haven.getMoneroWordList(language);
|
||||
return haven!.getMoneroWordList(language);
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
@@ -31,9 +32,9 @@ class SeedValidator extends Validator<MnemonicItem> {
|
||||
|
||||
static List<String> getBitcoinWordList(String language) {
|
||||
assert(language.toLowerCase() == LanguageList.english.toLowerCase());
|
||||
return bitcoin.getWordList();
|
||||
return bitcoin!.getWordList();
|
||||
}
|
||||
|
||||
@override
|
||||
bool isValid(MnemonicItem value) => _words.contains(value.text);
|
||||
bool isValid(MnemonicItem? value) => _words.contains(value?.text);
|
||||
}
|
||||
|
||||
@@ -33,4 +33,6 @@ String syncStatusTitle(SyncStatus syncStatus) {
|
||||
if (syncStatus is LostConnectionSyncStatus) {
|
||||
return S.current.sync_status_failed_connect;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
+12
-12
@@ -1,13 +1,13 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
abstract class Validator<T> {
|
||||
Validator({@required this.errorMessage});
|
||||
Validator({required this.errorMessage});
|
||||
|
||||
final String errorMessage;
|
||||
|
||||
bool isValid(T value);
|
||||
bool isValid(T? value);
|
||||
|
||||
String call(T value) => !isValid(value) ? errorMessage : null;
|
||||
String? call(T? value) => !isValid(value) ? errorMessage : null;
|
||||
}
|
||||
|
||||
class TextValidator extends Validator<String> {
|
||||
@@ -15,28 +15,28 @@ class TextValidator extends Validator<String> {
|
||||
{this.minLength,
|
||||
this.maxLength,
|
||||
this.pattern,
|
||||
String errorMessage = '',
|
||||
this.length,
|
||||
this.isAutovalidate = false,
|
||||
String errorMessage})
|
||||
this.isAutovalidate = false})
|
||||
: super(errorMessage: errorMessage);
|
||||
|
||||
final int minLength;
|
||||
final int maxLength;
|
||||
final List<int> length;
|
||||
final int? minLength;
|
||||
final int? maxLength;
|
||||
final List<int>? length;
|
||||
final bool isAutovalidate;
|
||||
String pattern;
|
||||
String? pattern;
|
||||
|
||||
@override
|
||||
bool isValid(String value) {
|
||||
bool isValid(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return isAutovalidate ? true : false;
|
||||
}
|
||||
|
||||
return value.length > (minLength ?? 0) &&
|
||||
(length?.contains(value.length) ?? true) &&
|
||||
((maxLength ?? 0) > 0 ? (value.length <= maxLength) : true) &&
|
||||
((maxLength ?? 0) > 0 ? (value.length <= maxLength!) : true) &&
|
||||
(pattern != null ? match(value) : true);
|
||||
}
|
||||
|
||||
bool match(String value) => RegExp(pattern).hasMatch(value);
|
||||
bool match(String value) => pattern != null ? RegExp(pattern!).hasMatch(value) : false;
|
||||
}
|
||||
|
||||
@@ -14,15 +14,13 @@ import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
class WalletCreationService {
|
||||
WalletCreationService(
|
||||
{WalletType initialType,
|
||||
this.secureStorage,
|
||||
this.keyService,
|
||||
this.sharedPreferences,
|
||||
this.walletInfoSource})
|
||||
{required WalletType initialType,
|
||||
required this.secureStorage,
|
||||
required this.keyService,
|
||||
required this.sharedPreferences,
|
||||
required this.walletInfoSource})
|
||||
: type = initialType {
|
||||
if (type != null) {
|
||||
changeWalletType(type: type);
|
||||
}
|
||||
changeWalletType(type: type);
|
||||
}
|
||||
|
||||
WalletType type;
|
||||
@@ -30,11 +28,11 @@ class WalletCreationService {
|
||||
final SharedPreferences sharedPreferences;
|
||||
final KeyService keyService;
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
WalletService _service;
|
||||
WalletService? _service;
|
||||
|
||||
static const _isNewMoneroWalletPasswordUpdated = true;
|
||||
|
||||
void changeWalletType({@required WalletType type}) {
|
||||
void changeWalletType({required WalletType type}) {
|
||||
this.type = type;
|
||||
_service = getIt.get<WalletService>(param1: type);
|
||||
}
|
||||
@@ -46,6 +44,12 @@ class WalletCreationService {
|
||||
.any((walletInfo) => walletInfo.name.toLowerCase() == walletName);
|
||||
}
|
||||
|
||||
bool typeExists(WalletType type) {
|
||||
return walletInfoSource
|
||||
.values
|
||||
.any((walletInfo) => walletInfo.type == type);
|
||||
}
|
||||
|
||||
void checkIfExists(String name) {
|
||||
if (exists(name)) {
|
||||
throw Exception('Wallet with name ${name} already exists!');
|
||||
@@ -58,7 +62,7 @@ class WalletCreationService {
|
||||
credentials.password = password;
|
||||
await keyService.saveWalletPassword(
|
||||
password: password, walletName: credentials.name);
|
||||
final wallet = await _service.create(credentials);
|
||||
final wallet = await _service!.create(credentials);
|
||||
|
||||
if (wallet.type == WalletType.monero) {
|
||||
await sharedPreferences
|
||||
@@ -76,7 +80,7 @@ class WalletCreationService {
|
||||
credentials.password = password;
|
||||
await keyService.saveWalletPassword(
|
||||
password: password, walletName: credentials.name);
|
||||
final wallet = await _service.restoreFromKeys(credentials);
|
||||
final wallet = await _service!.restoreFromKeys(credentials);
|
||||
|
||||
if (wallet.type == WalletType.monero) {
|
||||
await sharedPreferences
|
||||
@@ -94,7 +98,7 @@ class WalletCreationService {
|
||||
credentials.password = password;
|
||||
await keyService.saveWalletPassword(
|
||||
password: password, walletName: credentials.name);
|
||||
final wallet = await _service.restoreFromSeed(credentials);
|
||||
final wallet = await _service!.restoreFromSeed(credentials);
|
||||
|
||||
if (wallet.type == WalletType.monero) {
|
||||
await sharedPreferences
|
||||
|
||||
@@ -7,7 +7,7 @@ class WalletCreating extends WalletCreationState {}
|
||||
class WalletCreatedSuccessfully extends WalletCreationState {}
|
||||
|
||||
class WalletCreationFailure extends WalletCreationState {
|
||||
WalletCreationFailure({@required this.error});
|
||||
WalletCreationFailure({required this.error});
|
||||
|
||||
final String error;
|
||||
}
|
||||
@@ -17,18 +17,15 @@ class WalletLoadingService {
|
||||
final WalletService Function(WalletType type) walletServiceFactory;
|
||||
|
||||
Future<WalletBase> load(WalletType type, String name) async {
|
||||
if (walletServiceFactory == null) {
|
||||
throw Exception('WalletLoadingService.walletServiceFactory is not set');
|
||||
}
|
||||
final walletService = walletServiceFactory?.call(type);
|
||||
final walletService = walletServiceFactory.call(type);
|
||||
final password = await keyService.getWalletPassword(walletName: name);
|
||||
final wallet = await walletService.openWallet(name, password);
|
||||
final wallet = await walletService.openWallet(name, password);
|
||||
|
||||
if (type == WalletType.monero) {
|
||||
await upateMoneroWalletPassword(wallet);
|
||||
}
|
||||
if (type == WalletType.monero) {
|
||||
await upateMoneroWalletPassword(wallet);
|
||||
}
|
||||
|
||||
return wallet;
|
||||
return wallet;
|
||||
}
|
||||
|
||||
Future<void> upateMoneroWalletPassword(WalletBase wallet) async {
|
||||
|
||||
+103
-72
@@ -2,13 +2,17 @@ import 'package:cake_wallet/core/yat_service.dart';
|
||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||
import 'package:cake_wallet/entities/wake_lock.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_anypay.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_category.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_tip.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/onramper_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_filter_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_custom_redeem_view_model.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_service.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_api.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_merchant.dart';
|
||||
@@ -154,26 +158,26 @@ import 'package:cake_wallet/core/wallet_loading_service.dart';
|
||||
final getIt = GetIt.instance;
|
||||
|
||||
var _isSetupFinished = false;
|
||||
Box<WalletInfo> _walletInfoSource;
|
||||
Box<Node> _nodeSource;
|
||||
Box<Contact> _contactSource;
|
||||
Box<Trade> _tradesSource;
|
||||
Box<Template> _templates;
|
||||
Box<ExchangeTemplate> _exchangeTemplates;
|
||||
Box<TransactionDescription> _transactionDescriptionBox;
|
||||
Box<Order> _ordersSource;
|
||||
Box<UnspentCoinsInfo> _unspentCoinsInfoSource;
|
||||
late Box<WalletInfo> _walletInfoSource;
|
||||
late Box<Node> _nodeSource;
|
||||
late Box<Contact> _contactSource;
|
||||
late Box<Trade> _tradesSource;
|
||||
late Box<Template> _templates;
|
||||
late Box<ExchangeTemplate> _exchangeTemplates;
|
||||
late Box<TransactionDescription> _transactionDescriptionBox;
|
||||
late Box<Order> _ordersSource;
|
||||
late Box<UnspentCoinsInfo>? _unspentCoinsInfoSource;
|
||||
|
||||
Future setup(
|
||||
{Box<WalletInfo> walletInfoSource,
|
||||
Box<Node> nodeSource,
|
||||
Box<Contact> contactSource,
|
||||
Box<Trade> tradesSource,
|
||||
Box<Template> templates,
|
||||
Box<ExchangeTemplate> exchangeTemplates,
|
||||
Box<TransactionDescription> transactionDescriptionBox,
|
||||
Box<Order> ordersSource,
|
||||
Box<UnspentCoinsInfo> unspentCoinsInfoSource}) async {
|
||||
{required Box<WalletInfo> walletInfoSource,
|
||||
required Box<Node> nodeSource,
|
||||
required Box<Contact> contactSource,
|
||||
required Box<Trade> tradesSource,
|
||||
required Box<Template> templates,
|
||||
required Box<ExchangeTemplate> exchangeTemplates,
|
||||
required Box<TransactionDescription> transactionDescriptionBox,
|
||||
required Box<Order> ordersSource,
|
||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource}) async {
|
||||
_walletInfoSource = walletInfoSource;
|
||||
_nodeSource = nodeSource;
|
||||
_contactSource = contactSource;
|
||||
@@ -326,9 +330,9 @@ Future setup(
|
||||
.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
}
|
||||
|
||||
ReactionDisposer _reaction;
|
||||
_reaction = reaction((_) => appStore.wallet, (Object _) {
|
||||
_reaction?.reaction?.dispose();
|
||||
ReactionDisposer? _reaction;
|
||||
_reaction = reaction((_) => appStore.wallet, (Object? _) {
|
||||
_reaction?.reaction.dispose();
|
||||
authStore.allowed();
|
||||
});
|
||||
}, closable: false),
|
||||
@@ -352,7 +356,7 @@ Future setup(
|
||||
|
||||
getIt.registerFactoryParam<WalletAddressEditOrCreateViewModel, dynamic, void>(
|
||||
(dynamic item, _) => WalletAddressEditOrCreateViewModel(
|
||||
wallet: getIt.get<AppStore>().wallet, item: item));
|
||||
wallet: getIt.get<AppStore>().wallet!, item: item));
|
||||
|
||||
getIt.registerFactoryParam<AddressEditOrCreatePage, dynamic, void>(
|
||||
(dynamic item, _) => AddressEditOrCreatePage(
|
||||
@@ -360,13 +364,13 @@ Future setup(
|
||||
getIt.get<WalletAddressEditOrCreateViewModel>(param1: item)));
|
||||
|
||||
getIt.registerFactory<SendTemplateViewModel>(() => SendTemplateViewModel(
|
||||
getIt.get<AppStore>().wallet,
|
||||
getIt.get<AppStore>().wallet!,
|
||||
getIt.get<AppStore>().settingsStore,
|
||||
getIt.get<SendTemplateStore>(),
|
||||
getIt.get<FiatConversionStore>()));
|
||||
|
||||
getIt.registerFactory<SendViewModel>(() => SendViewModel(
|
||||
getIt.get<AppStore>().wallet,
|
||||
getIt.get<AppStore>().wallet!,
|
||||
getIt.get<AppStore>().settingsStore,
|
||||
getIt.get<SendTemplateViewModel>(),
|
||||
getIt.get<FiatConversionStore>(),
|
||||
@@ -392,14 +396,13 @@ Future setup(
|
||||
WalletListPage(walletListViewModel: getIt.get<WalletListViewModel>()));
|
||||
|
||||
getIt.registerFactory(() {
|
||||
final wallet = getIt.get<AppStore>().wallet;
|
||||
final wallet = getIt.get<AppStore>().wallet!;
|
||||
|
||||
if (wallet.type == WalletType.monero || wallet.type == WalletType.haven) {
|
||||
return MoneroAccountListViewModel(wallet);
|
||||
}
|
||||
|
||||
// FIXME: throw exception.
|
||||
return null;
|
||||
throw Exception('Unexpected wallet type: ${wallet.type} for generate MoneroAccountListViewModel');
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => MoneroAccountListPage(
|
||||
@@ -421,29 +424,29 @@ Future setup(
|
||||
getIt.get<MoneroAccountEditOrCreateViewModel>()));*/
|
||||
|
||||
getIt.registerFactoryParam<MoneroAccountEditOrCreateViewModel,
|
||||
AccountListItem, void>(
|
||||
(AccountListItem account, _) => MoneroAccountEditOrCreateViewModel(
|
||||
monero.getAccountList(getIt.get<AppStore>().wallet),
|
||||
haven?.getAccountList(getIt.get<AppStore>().wallet),
|
||||
wallet: getIt.get<AppStore>().wallet,
|
||||
AccountListItem?, void>(
|
||||
(AccountListItem? account, _) => MoneroAccountEditOrCreateViewModel(
|
||||
monero!.getAccountList(getIt.get<AppStore>().wallet!),
|
||||
haven?.getAccountList(getIt.get<AppStore>().wallet!),
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
accountListItem: account));
|
||||
|
||||
getIt.registerFactoryParam<MoneroAccountEditOrCreatePage, AccountListItem,
|
||||
getIt.registerFactoryParam<MoneroAccountEditOrCreatePage, AccountListItem?,
|
||||
void>(
|
||||
(AccountListItem account, _) => MoneroAccountEditOrCreatePage(
|
||||
(AccountListItem? account, _) => MoneroAccountEditOrCreatePage(
|
||||
moneroAccountCreationViewModel:
|
||||
getIt.get<MoneroAccountEditOrCreateViewModel>(param1: account)));
|
||||
|
||||
getIt.registerFactory(() {
|
||||
final appStore = getIt.get<AppStore>();
|
||||
final yatStore = getIt.get<YatStore>();
|
||||
return SettingsViewModel(appStore.settingsStore, yatStore, appStore.wallet);
|
||||
return SettingsViewModel(appStore.settingsStore, yatStore, appStore.wallet!);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => SettingsPage(getIt.get<SettingsViewModel>()));
|
||||
|
||||
getIt
|
||||
.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet));
|
||||
.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactoryParam<WalletSeedPage, bool, void>(
|
||||
(bool isWalletCreated, _) => WalletSeedPage(
|
||||
@@ -451,12 +454,12 @@ Future setup(
|
||||
isNewWalletCreated: isWalletCreated));
|
||||
|
||||
getIt
|
||||
.registerFactory(() => WalletKeysViewModel(getIt.get<AppStore>().wallet));
|
||||
.registerFactory(() => WalletKeysViewModel(getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory(() => WalletKeysPage(getIt.get<WalletKeysViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<ContactViewModel, ContactRecord, void>(
|
||||
(ContactRecord contact, _) =>
|
||||
getIt.registerFactoryParam<ContactViewModel, ContactRecord?, void>(
|
||||
(ContactRecord? contact, _) =>
|
||||
ContactViewModel(_contactSource, contact: contact));
|
||||
|
||||
getIt.registerFactory(
|
||||
@@ -466,33 +469,40 @@ Future setup(
|
||||
(bool isEditable, _) => ContactListPage(getIt.get<ContactListViewModel>(),
|
||||
isEditable: isEditable));
|
||||
|
||||
getIt.registerFactoryParam<ContactPage, ContactRecord, void>(
|
||||
(ContactRecord contact, _) =>
|
||||
getIt.registerFactoryParam<ContactPage, ContactRecord?, void>(
|
||||
(ContactRecord? contact, _) =>
|
||||
ContactPage(getIt.get<ContactViewModel>(param1: contact)));
|
||||
|
||||
getIt.registerFactory(() {
|
||||
final appStore = getIt.get<AppStore>();
|
||||
return NodeListViewModel(
|
||||
_nodeSource, appStore.wallet, appStore.settingsStore);
|
||||
_nodeSource, appStore.wallet!, appStore.settingsStore);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => NodeListPage(getIt.get<NodeListViewModel>()));
|
||||
|
||||
getIt.registerFactory(() =>
|
||||
NodeCreateOrEditViewModel(_nodeSource, getIt.get<AppStore>().wallet));
|
||||
NodeCreateOrEditViewModel(_nodeSource, getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => NodeCreateOrEditPage(getIt.get<NodeCreateOrEditViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => OnRamperPage(
|
||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory(() => ExchangeViewModel(
|
||||
getIt.get<AppStore>().wallet,
|
||||
getIt.get<AppStore>().wallet!,
|
||||
_tradesSource,
|
||||
getIt.get<ExchangeTemplateStore>(),
|
||||
getIt.get<TradesStore>(),
|
||||
getIt.get<AppStore>().settingsStore));
|
||||
getIt.get<AppStore>().settingsStore,
|
||||
getIt.get<SharedPreferences>(),
|
||||
getIt.get<SettingsViewModel>(),
|
||||
));
|
||||
|
||||
getIt.registerFactory(() => ExchangeTradeViewModel(
|
||||
wallet: getIt.get<AppStore>().wallet,
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
trades: _tradesSource,
|
||||
tradesStore: getIt.get<TradesStore>(),
|
||||
sendViewModel: getIt.get<SendViewModel>()));
|
||||
@@ -512,17 +522,17 @@ Future setup(
|
||||
(WalletType param1, __) {
|
||||
switch (param1) {
|
||||
case WalletType.haven:
|
||||
return haven.createHavenWalletService(_walletInfoSource);
|
||||
return haven!.createHavenWalletService(_walletInfoSource);
|
||||
case WalletType.monero:
|
||||
return monero.createMoneroWalletService(_walletInfoSource);
|
||||
return monero!.createMoneroWalletService(_walletInfoSource);
|
||||
case WalletType.bitcoin:
|
||||
return bitcoin.createBitcoinWalletService(
|
||||
_walletInfoSource, _unspentCoinsInfoSource);
|
||||
return bitcoin!.createBitcoinWalletService(
|
||||
_walletInfoSource, _unspentCoinsInfoSource!);
|
||||
case WalletType.litecoin:
|
||||
return bitcoin.createLitecoinWalletService(
|
||||
_walletInfoSource, _unspentCoinsInfoSource);
|
||||
return bitcoin!.createLitecoinWalletService(
|
||||
_walletInfoSource, _unspentCoinsInfoSource!);
|
||||
default:
|
||||
return null;
|
||||
throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -535,7 +545,7 @@ Future setup(
|
||||
getIt.get<SetupPinCodeViewModel>(),
|
||||
onSuccessfulPinSetup: onSuccessfulPinSetup));
|
||||
|
||||
getIt.registerFactory(() => RescanViewModel(getIt.get<AppStore>().wallet));
|
||||
getIt.registerFactory(() => RescanViewModel(getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory(() => RescanPage(getIt.get<RescanViewModel>()));
|
||||
|
||||
@@ -552,7 +562,7 @@ Future setup(
|
||||
getIt
|
||||
.registerFactoryParam<TransactionDetailsViewModel, TransactionInfo, void>(
|
||||
(TransactionInfo transactionInfo, _) {
|
||||
final wallet = getIt.get<AppStore>().wallet;
|
||||
final wallet = getIt.get<AppStore>().wallet!;
|
||||
return TransactionDetailsViewModel(
|
||||
transactionInfo: transactionInfo,
|
||||
transactionDescriptionBox: _transactionDescriptionBox,
|
||||
@@ -566,15 +576,15 @@ Future setup(
|
||||
getIt.get<TransactionDetailsViewModel>(param1: transactionInfo)));
|
||||
|
||||
getIt.registerFactoryParam<NewWalletTypePage,
|
||||
void Function(BuildContext, WalletType), bool>(
|
||||
(para1, param2) => NewWalletTypePage(getIt.get<WalletNewVM>(),
|
||||
onTypeSelected: para1, isNewWallet: param2));
|
||||
void Function(BuildContext, WalletType), void>(
|
||||
(param1, _) => NewWalletTypePage(onTypeSelected: param1));
|
||||
|
||||
getIt.registerFactoryParam<PreSeedPage, WalletType, void>(
|
||||
(WalletType type, _) => PreSeedPage(type));
|
||||
|
||||
getIt.registerFactoryParam<TradeDetailsViewModel, Trade, void>((trade, _) =>
|
||||
TradeDetailsViewModel(tradeForDetails: trade, trades: _tradesSource));
|
||||
TradeDetailsViewModel(tradeForDetails: trade, trades: _tradesSource,
|
||||
settingsStore: getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactory(() => BackupService(
|
||||
getIt.get<FlutterSecureStorage>(),
|
||||
@@ -587,6 +597,9 @@ Future setup(
|
||||
|
||||
getIt.registerFactory(() => BackupPage(getIt.get<BackupViewModel>()));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => EditBackupPasswordViewModel(getIt.get<FlutterSecureStorage>(), getIt.get<SecretStore>()));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>()));
|
||||
|
||||
@@ -608,7 +621,7 @@ Future setup(
|
||||
|
||||
return BuyViewModel(_ordersSource, getIt.get<OrdersStore>(),
|
||||
getIt.get<SettingsStore>(), getIt.get<BuyAmountViewModel>(),
|
||||
wallet: wallet);
|
||||
wallet: wallet!);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() {
|
||||
@@ -625,7 +638,7 @@ Future setup(
|
||||
getIt.registerFactoryParam<OrderDetailsViewModel, Order, void>((order, _) {
|
||||
final wallet = getIt.get<AppStore>().wallet;
|
||||
|
||||
return OrderDetailsViewModel(wallet: wallet, orderForDetails: order);
|
||||
return OrderDetailsViewModel(wallet: wallet!, orderForDetails: order);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<OrderDetailsPage, Order, void>((Order order, _) =>
|
||||
@@ -639,7 +652,7 @@ Future setup(
|
||||
final wallet = getIt.get<AppStore>().wallet;
|
||||
|
||||
return UnspentCoinsListViewModel(
|
||||
wallet: wallet, unspentCoinsInfo: _unspentCoinsInfoSource);
|
||||
wallet: wallet!, unspentCoinsInfo: _unspentCoinsInfoSource!);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => UnspentCoinsListPage(
|
||||
@@ -665,7 +678,7 @@ Future setup(
|
||||
getIt.registerFactory(() => YatService());
|
||||
|
||||
getIt.registerFactory(() => AddressResolver(yatService: getIt.get<YatService>(),
|
||||
walletType: getIt.get<AppStore>().wallet.type));
|
||||
walletType: getIt.get<AppStore>().wallet!.type));
|
||||
|
||||
getIt.registerFactoryParam<FullscreenQRPage, String, bool>(
|
||||
(String qrData, bool isLight) => FullscreenQRPage(qrData: qrData, isLight: isLight,));
|
||||
@@ -681,9 +694,7 @@ Future setup(
|
||||
() => IoniaAnyPay(
|
||||
getIt.get<IoniaService>(),
|
||||
getIt.get<AnyPayApi>(),
|
||||
getIt.get<AppStore>().wallet));
|
||||
|
||||
getIt.registerFactory<IoniaFilterViewModel>(() => IoniaFilterViewModel());
|
||||
getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory(() => IoniaGiftCardsListViewModel(ioniaService: getIt.get<IoniaService>()));
|
||||
|
||||
@@ -734,15 +745,35 @@ Future setup(
|
||||
giftCard: giftCard);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomTipViewModel, List, void>((List args, _) {
|
||||
final amount = args[0] as double;
|
||||
final merchant = args[1] as IoniaMerchant;
|
||||
final tip = args[2] as IoniaTip;
|
||||
|
||||
return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaGiftCardDetailPage, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) {
|
||||
return IoniaGiftCardDetailPage(getIt.get<IoniaGiftCardDetailsViewModel>(param1: giftCard));
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomTipPage, List, void>((List args, _) {
|
||||
final amount = args.first as String;
|
||||
final merchant = args.last as IoniaMerchant;
|
||||
getIt.registerFactoryParam<IoniaMoreOptionsPage, List, void>((List args, _){
|
||||
final giftCard = args.first as IoniaGiftCard;
|
||||
|
||||
return IoniaCustomTipPage(getIt.get<IoniaMerchPurchaseViewModel>(param1: amount, param2: merchant));
|
||||
return IoniaMoreOptionsPage(giftCard);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) => IoniaCustomRedeemViewModel(giftCard));
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _){
|
||||
final giftCard = args.first as IoniaGiftCard;
|
||||
|
||||
return IoniaCustomRedeemPage(getIt.get<IoniaCustomRedeemViewModel>(param1: giftCard) );
|
||||
});
|
||||
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomTipPage, List, void>((List args, _) {
|
||||
return IoniaCustomTipPage(getIt.get<IoniaCustomTipViewModel>(param1: args));
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => IoniaManageCardsPage(getIt.get<IoniaGiftCardsListViewModel>()));
|
||||
|
||||
@@ -18,7 +18,7 @@ int serializeActionlistDisplayModes(List<ActionListDisplayMode> modes) {
|
||||
}
|
||||
|
||||
List<ActionListDisplayMode> deserializeActionlistDisplayModes(int raw) {
|
||||
final modes = List<ActionListDisplayMode>();
|
||||
final modes = <ActionListDisplayMode>[];
|
||||
|
||||
if (raw == 1 || raw - 10 == 1) {
|
||||
modes.add(ActionListDisplayMode.trades);
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cw_core/enumerable_item.dart';
|
||||
|
||||
class BalanceDisplayMode extends EnumerableItem<int> with Serializable<int> {
|
||||
const BalanceDisplayMode({@required String title, @required int raw})
|
||||
const BalanceDisplayMode({required String title, required int raw})
|
||||
: super(title: title, raw: raw);
|
||||
|
||||
static const all = [
|
||||
@@ -18,7 +18,7 @@ class BalanceDisplayMode extends EnumerableItem<int> with Serializable<int> {
|
||||
static const displayableBalance =
|
||||
BalanceDisplayMode(raw: 3, title: 'Displayable Balance');
|
||||
|
||||
static BalanceDisplayMode deserialize({int raw}) {
|
||||
static BalanceDisplayMode deserialize({required int raw}) {
|
||||
switch (raw) {
|
||||
case 0:
|
||||
return fullBalance;
|
||||
@@ -29,7 +29,7 @@ class BalanceDisplayMode extends EnumerableItem<int> with Serializable<int> {
|
||||
case 3:
|
||||
return displayableBalance;
|
||||
default:
|
||||
return null;
|
||||
throw Exception('Unexpected token: $raw for BalanceDisplayMode deserialize');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,9 @@ class BiometricAuth {
|
||||
try {
|
||||
return await _localAuth.authenticate(
|
||||
localizedReason: S.current.biometric_auth_reason,
|
||||
useErrorDialogs: true,
|
||||
stickyAuth: false);
|
||||
options: AuthenticationOptions(
|
||||
useErrorDialogs: true,
|
||||
stickyAuth: false));
|
||||
} on PlatformException catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
String calculateFiatAmount({double price, String cryptoAmount}) {
|
||||
String calculateFiatAmount({double? price, String? cryptoAmount}) {
|
||||
if (price == null || cryptoAmount == null) {
|
||||
return '0.00';
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
String calculateFiatAmountRaw({double price, double cryptoAmount}) {
|
||||
String calculateFiatAmountRaw({required double cryptoAmount, double? price}) {
|
||||
if (price == null) {
|
||||
return '0.00';
|
||||
}
|
||||
|
||||
@@ -8,20 +8,23 @@ part 'contact.g.dart';
|
||||
|
||||
@HiveType(typeId: Contact.typeId)
|
||||
class Contact extends HiveObject with Keyable {
|
||||
Contact({@required this.name, @required this.address, CryptoCurrency type})
|
||||
: raw = type?.raw;
|
||||
Contact({required this.name, required this.address, CryptoCurrency? type}) {
|
||||
if (type != null) {
|
||||
raw = type.raw;
|
||||
}
|
||||
}
|
||||
|
||||
static const typeId = 0;
|
||||
static const boxName = 'Contacts';
|
||||
|
||||
@HiveField(0)
|
||||
@HiveField(0, defaultValue: '')
|
||||
String name;
|
||||
|
||||
@HiveField(1)
|
||||
@HiveField(1, defaultValue: '')
|
||||
String address;
|
||||
|
||||
@HiveField(2)
|
||||
int raw;
|
||||
@HiveField(2, defaultValue: 0)
|
||||
late int raw;
|
||||
|
||||
CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw);
|
||||
|
||||
@@ -34,6 +37,6 @@ class Contact extends HiveObject with Keyable {
|
||||
@override
|
||||
int get hashCode => key.hashCode;
|
||||
|
||||
void updateCryptoCurrency({@required CryptoCurrency currency}) =>
|
||||
void updateCryptoCurrency({required CryptoCurrency currency}) =>
|
||||
raw = currency.raw;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
abstract class ContactBase {
|
||||
ContactBase(this.name, this.address, this.type);
|
||||
|
||||
String name;
|
||||
|
||||
String address;
|
||||
|
||||
@@ -13,7 +13,10 @@ abstract class ContactRecordBase extends Record<Contact>
|
||||
with Store
|
||||
implements ContactBase {
|
||||
ContactRecordBase(Box<Contact> source, Contact original)
|
||||
: super(source, original);
|
||||
: name = original.name,
|
||||
address = original.address,
|
||||
type = original.type,
|
||||
super(source, original);
|
||||
|
||||
@override
|
||||
@observable
|
||||
|
||||
@@ -18,6 +18,7 @@ import 'package:cake_wallet/entities/fs_migration.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:encrypt/encrypt.dart' as encrypt;
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
const newCakeWalletMoneroUri = 'xmr-node.cakewallet.com:18081';
|
||||
const cakeWalletBitcoinElectrumUri = 'electrum.cakewallet.com:50002';
|
||||
@@ -25,13 +26,13 @@ const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002';
|
||||
const havenDefaultNodeUri = 'nodes.havenprotocol.org:443';
|
||||
|
||||
Future defaultSettingsMigration(
|
||||
{@required int version,
|
||||
@required SharedPreferences sharedPreferences,
|
||||
@required FlutterSecureStorage secureStorage,
|
||||
@required Box<Node> nodes,
|
||||
@required Box<WalletInfo> walletInfoSource,
|
||||
@required Box<Trade> tradeSource,
|
||||
@required Box<Contact> contactSource}) async {
|
||||
{required int version,
|
||||
required SharedPreferences sharedPreferences,
|
||||
required FlutterSecureStorage secureStorage,
|
||||
required Box<Node> nodes,
|
||||
required Box<WalletInfo> walletInfoSource,
|
||||
required Box<Trade> tradeSource,
|
||||
required Box<Contact> contactSource}) async {
|
||||
if (Platform.isIOS) {
|
||||
await ios_migrate_v1(walletInfoSource, tradeSource, contactSource);
|
||||
}
|
||||
@@ -56,7 +57,7 @@ Future defaultSettingsMigration(
|
||||
FiatCurrency.usd.toString());
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentTransactionPriorityKeyLegacy,
|
||||
monero.getDefaultTransactionPriority().raw);
|
||||
monero!.getDefaultTransactionPriority().raw);
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentBalanceDisplayModeKey,
|
||||
BalanceDisplayMode.availableBalance.raw);
|
||||
@@ -147,7 +148,7 @@ Future defaultSettingsMigration(
|
||||
'current_default_settings_migration_version', version);
|
||||
}
|
||||
|
||||
Future<void> replaceNodesMigration({@required Box<Node> nodes}) async {
|
||||
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),
|
||||
@@ -170,39 +171,33 @@ Future<void> replaceNodesMigration({@required Box<Node> nodes}) async {
|
||||
}
|
||||
|
||||
Future<void> changeMoneroCurrentNodeToDefault(
|
||||
{@required SharedPreferences sharedPreferences,
|
||||
@required Box<Node> nodes}) async {
|
||||
{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}) {
|
||||
return nodes.values.firstWhere(
|
||||
(Node node) => node.uri == cakeWalletBitcoinElectrumUri,
|
||||
orElse: () => null) ??
|
||||
nodes.values.firstWhere((node) => node.type == WalletType.bitcoin,
|
||||
orElse: () => null);
|
||||
Node? getBitcoinDefaultElectrumServer({required Box<Node> nodes}) {
|
||||
return nodes.values.firstWhereOrNull(
|
||||
(Node node) => node.uriRaw == cakeWalletBitcoinElectrumUri)
|
||||
?? nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoin);
|
||||
}
|
||||
|
||||
Node getLitecoinDefaultElectrumServer({@required Box<Node> nodes}) {
|
||||
return nodes.values.firstWhere(
|
||||
(Node node) => node.uri == cakeWalletLitecoinElectrumUri,
|
||||
orElse: () => null) ??
|
||||
nodes.values.firstWhere((node) => node.type == WalletType.litecoin,
|
||||
orElse: () => null);
|
||||
Node? getLitecoinDefaultElectrumServer({required Box<Node> nodes}) {
|
||||
return nodes.values.firstWhereOrNull(
|
||||
(Node node) => node.uriRaw == cakeWalletLitecoinElectrumUri)
|
||||
?? nodes.values.firstWhereOrNull((node) => node.type == WalletType.litecoin);
|
||||
}
|
||||
|
||||
Node getHavenDefaultNode({@required Box<Node> nodes}) {
|
||||
return nodes.values.firstWhere(
|
||||
(Node node) => node.uriRaw == havenDefaultNodeUri,
|
||||
orElse: () => null) ??
|
||||
nodes.values.firstWhere((node) => node.type == WalletType.haven,
|
||||
orElse: () => null);
|
||||
Node? getHavenDefaultNode({required Box<Node> nodes}) {
|
||||
return nodes.values.firstWhereOrNull(
|
||||
(Node node) => node.uriRaw == havenDefaultNodeUri)
|
||||
?? nodes.values.firstWhereOrNull((node) => node.type == WalletType.haven);
|
||||
}
|
||||
|
||||
Node getMoneroDefaultNode({@required Box<Node> nodes}) {
|
||||
Node getMoneroDefaultNode({required Box<Node> nodes}) {
|
||||
final timeZone = DateTime.now().timeZoneOffset.inHours;
|
||||
var nodeUri = '';
|
||||
|
||||
@@ -214,14 +209,17 @@ Node getMoneroDefaultNode({@required Box<Node> nodes}) {
|
||||
nodeUri = 'xmr-node-usa-east.cakewallet.com:18081';
|
||||
}
|
||||
|
||||
return nodes.values
|
||||
.firstWhere((Node node) => node.uri == nodeUri, orElse: () => null) ??
|
||||
nodes.values.first;
|
||||
try {
|
||||
return nodes.values
|
||||
.firstWhere((Node node) => node.uriRaw == nodeUri);
|
||||
} catch(_) {
|
||||
return nodes.values.first;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> changeBitcoinCurrentElectrumServerToDefault(
|
||||
{@required SharedPreferences sharedPreferences,
|
||||
@required Box<Node> nodes}) async {
|
||||
{required SharedPreferences sharedPreferences,
|
||||
required Box<Node> nodes}) async {
|
||||
final server = getBitcoinDefaultElectrumServer(nodes: nodes);
|
||||
final serverId = server?.key as int ?? 0;
|
||||
|
||||
@@ -229,8 +227,8 @@ Future<void> changeBitcoinCurrentElectrumServerToDefault(
|
||||
}
|
||||
|
||||
Future<void> changeLitecoinCurrentElectrumServerToDefault(
|
||||
{@required SharedPreferences sharedPreferences,
|
||||
@required Box<Node> nodes}) async {
|
||||
{required SharedPreferences sharedPreferences,
|
||||
required Box<Node> nodes}) async {
|
||||
final server = getLitecoinDefaultElectrumServer(nodes: nodes);
|
||||
final serverId = server?.key as int ?? 0;
|
||||
|
||||
@@ -238,8 +236,8 @@ Future<void> changeLitecoinCurrentElectrumServerToDefault(
|
||||
}
|
||||
|
||||
Future<void> changeHavenCurrentNodeToDefault(
|
||||
{@required SharedPreferences sharedPreferences,
|
||||
@required Box<Node> nodes}) async {
|
||||
{required SharedPreferences sharedPreferences,
|
||||
required Box<Node> nodes}) async {
|
||||
final node = getHavenDefaultNode(nodes: nodes);
|
||||
final nodeId = node?.key as int ?? 0;
|
||||
|
||||
@@ -247,8 +245,8 @@ Future<void> changeHavenCurrentNodeToDefault(
|
||||
}
|
||||
|
||||
Future<void> replaceDefaultNode(
|
||||
{@required SharedPreferences sharedPreferences,
|
||||
@required Box<Node> nodes}) async {
|
||||
{required SharedPreferences sharedPreferences,
|
||||
required Box<Node> nodes}) async {
|
||||
const nodesForReplace = <String>[
|
||||
'xmr-node-uk.cakewallet.com:18081',
|
||||
'eu-node.cakewallet.io:18081',
|
||||
@@ -256,9 +254,9 @@ Future<void> replaceDefaultNode(
|
||||
];
|
||||
final currentNodeId = sharedPreferences.getInt('current_node_id');
|
||||
final currentNode =
|
||||
nodes.values.firstWhere((Node node) => node.key == currentNodeId);
|
||||
nodes.values.firstWhereOrNull((Node node) => node.key == currentNodeId);
|
||||
final needToReplace =
|
||||
currentNode == null ? true : nodesForReplace.contains(currentNode.uri);
|
||||
currentNode == null ? true : nodesForReplace.contains(currentNode.uriRaw);
|
||||
|
||||
if (!needToReplace) {
|
||||
return;
|
||||
@@ -268,7 +266,7 @@ Future<void> replaceDefaultNode(
|
||||
sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
}
|
||||
|
||||
Future<void> updateNodeTypes({@required Box<Node> nodes}) async {
|
||||
Future<void> updateNodeTypes({required Box<Node> nodes}) async {
|
||||
nodes.values.forEach((node) async {
|
||||
if (node.type == null) {
|
||||
node.type = WalletType.monero;
|
||||
@@ -277,17 +275,17 @@ Future<void> updateNodeTypes({@required Box<Node> nodes}) async {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> addBitcoinElectrumServerList({@required Box<Node> nodes}) async {
|
||||
Future<void> addBitcoinElectrumServerList({required Box<Node> nodes}) async {
|
||||
final serverList = await loadBitcoinElectrumServerList();
|
||||
await nodes.addAll(serverList);
|
||||
}
|
||||
|
||||
Future<void> addLitecoinElectrumServerList({@required Box<Node> nodes}) async {
|
||||
Future<void> addLitecoinElectrumServerList({required Box<Node> nodes}) async {
|
||||
final serverList = await loadLitecoinElectrumServerList();
|
||||
await nodes.addAll(serverList);
|
||||
}
|
||||
|
||||
Future<void> addHavenNodeList({@required Box<Node> nodes}) async {
|
||||
Future<void> addHavenNodeList({required Box<Node> nodes}) async {
|
||||
final nodeList = await loadDefaultHavenNodes();
|
||||
await nodes.addAll(nodeList);
|
||||
}
|
||||
@@ -318,7 +316,7 @@ Future<void> addAddressesForMoneroWallets(
|
||||
|
||||
Future<void> updateDisplayModes(SharedPreferences sharedPreferences) async {
|
||||
final currentBalanceDisplayMode =
|
||||
sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey);
|
||||
sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey) ?? -1;
|
||||
final balanceDisplayMode = currentBalanceDisplayMode < 2 ? 3 : 2;
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentBalanceDisplayModeKey, balanceDisplayMode);
|
||||
@@ -338,11 +336,11 @@ Future<void> generateBackupPassword(FlutterSecureStorage secureStorage) async {
|
||||
Future<void> changeTransactionPriorityAndFeeRateKeys(
|
||||
SharedPreferences sharedPreferences) async {
|
||||
final legacyTransactionPriority = sharedPreferences
|
||||
.getInt(PreferencesKey.currentTransactionPriorityKeyLegacy);
|
||||
.getInt(PreferencesKey.currentTransactionPriorityKeyLegacy)!;
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.moneroTransactionPriority, legacyTransactionPriority);
|
||||
await sharedPreferences.setInt(PreferencesKey.bitcoinTransactionPriority,
|
||||
bitcoin.getMediumTransactionPriority().serialize());
|
||||
bitcoin!.getMediumTransactionPriority().serialize());
|
||||
}
|
||||
|
||||
Future<void> changeDefaultMoneroNode(
|
||||
@@ -383,18 +381,14 @@ Future<void> checkCurrentNodes(
|
||||
.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
|
||||
final currentHavenNodeId = sharedPreferences
|
||||
.getInt(PreferencesKey.currentHavenNodeIdKey);
|
||||
final currentMoneroNode = nodeSource.values.firstWhere(
|
||||
(node) => node.key == currentMoneroNodeId,
|
||||
orElse: () => null);
|
||||
final currentBitcoinElectrumServer = nodeSource.values.firstWhere(
|
||||
(node) => node.key == currentBitcoinElectrumSeverId,
|
||||
orElse: () => null);
|
||||
final currentLitecoinElectrumServer = nodeSource.values.firstWhere(
|
||||
(node) => node.key == currentLitecoinElectrumSeverId,
|
||||
orElse: () => null);
|
||||
final currentHavenNodeServer = nodeSource.values.firstWhere(
|
||||
(node) => node.key == currentHavenNodeId,
|
||||
orElse: () => null);
|
||||
final currentMoneroNode = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.key == currentMoneroNodeId);
|
||||
final currentBitcoinElectrumServer = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.key == currentBitcoinElectrumSeverId);
|
||||
final currentLitecoinElectrumServer = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.key == currentLitecoinElectrumSeverId);
|
||||
final currentHavenNodeServer = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.key == currentHavenNodeId);
|
||||
|
||||
if (currentMoneroNode == null) {
|
||||
final newCakeWalletNode =
|
||||
@@ -423,8 +417,7 @@ Future<void> checkCurrentNodes(
|
||||
}
|
||||
|
||||
if (currentHavenNodeServer == null) {
|
||||
final nodes = await loadDefaultHavenNodes();
|
||||
final node = nodes.first;
|
||||
final node = Node(uri: havenDefaultNodeUri, type: WalletType.haven);
|
||||
await nodeSource.add(node);
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentHavenNodeIdKey, node.key as int);
|
||||
@@ -435,12 +428,10 @@ Future<void> resetBitcoinElectrumServer(
|
||||
Box<Node> nodeSource, SharedPreferences sharedPreferences) async {
|
||||
final currentElectrumSeverId =
|
||||
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
|
||||
final oldElectrumServer = nodeSource.values.firstWhere(
|
||||
(node) => node.uri.toString().contains('electrumx.cakewallet.com'),
|
||||
orElse: () => null);
|
||||
var cakeWalletNode = nodeSource.values.firstWhere(
|
||||
(node) => node.uri.toString() == cakeWalletBitcoinElectrumUri,
|
||||
orElse: () => null);
|
||||
final oldElectrumServer = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.uri.toString().contains('electrumx.cakewallet.com'));
|
||||
var cakeWalletNode = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.uri.toString() == cakeWalletBitcoinElectrumUri);
|
||||
|
||||
if (cakeWalletNode == null) {
|
||||
cakeWalletNode =
|
||||
|
||||
@@ -16,6 +16,7 @@ extension Emoji on String {
|
||||
|
||||
bool _hasOnlyEmojis() {
|
||||
final parsedText = this.replaceAll(' ', '');
|
||||
if(parsedText.isEmpty) return false;
|
||||
for (final c in Characters(parsedText))
|
||||
if (!REGEX_EMOJI.hasMatch(c)) return false;
|
||||
return true;
|
||||
|
||||
+13
-11
@@ -1,8 +1,8 @@
|
||||
import 'package:encrypt/encrypt.dart';
|
||||
import 'package:password/password.dart';
|
||||
// import 'package:password/password.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
|
||||
String encrypt({String source, String key, int keyLength = 16}) {
|
||||
String encrypt({required String source, required String key, int keyLength = 16}) {
|
||||
final _key = Key.fromUtf8(key);
|
||||
final iv = IV.fromLength(keyLength);
|
||||
final encrypter = Encrypter(AES(_key));
|
||||
@@ -11,7 +11,7 @@ String encrypt({String source, String key, int keyLength = 16}) {
|
||||
return encrypted.base64;
|
||||
}
|
||||
|
||||
String decrypt({String source, String key, int keyLength = 16}) {
|
||||
String decrypt({required String source, required String key, int keyLength = 16}) {
|
||||
final _key = Key.fromUtf8(key);
|
||||
final iv = IV.fromLength(keyLength);
|
||||
final encrypter = Encrypter(AES(_key));
|
||||
@@ -20,33 +20,35 @@ String decrypt({String source, String key, int keyLength = 16}) {
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
String hash({String source}) {
|
||||
final algorithm = PBKDF2();
|
||||
final hash = Password.hash(source, algorithm);
|
||||
String hash({required String source}) {
|
||||
// FIX-ME: Uninplemented
|
||||
throw Exception('Unimplemented');
|
||||
// final algorithm = PBKDF2();
|
||||
// final hash = Password.hash(source, algorithm);
|
||||
|
||||
return hash;
|
||||
// return hash;
|
||||
}
|
||||
|
||||
String encodedPinCode({String pin}) {
|
||||
String encodedPinCode({required String pin}) {
|
||||
final source = '${secrets.salt}$pin';
|
||||
|
||||
return encrypt(source: source, key: secrets.key);
|
||||
}
|
||||
|
||||
String decodedPinCode({String pin}) {
|
||||
String decodedPinCode({required String pin}) {
|
||||
final decrypted = decrypt(source: pin, key: secrets.key);
|
||||
|
||||
return decrypted.substring(secrets.key.length, decrypted.length);
|
||||
}
|
||||
|
||||
String encodeWalletPassword({String password}) {
|
||||
String encodeWalletPassword({required String password}) {
|
||||
final source = password;
|
||||
final _key = secrets.shortKey + secrets.walletSalt;
|
||||
|
||||
return encrypt(source: source, key: _key);
|
||||
}
|
||||
|
||||
String decodeWalletPassword({String password}) {
|
||||
String decodeWalletPassword({required String password}) {
|
||||
final source = password;
|
||||
final _key = secrets.shortKey + secrets.walletSalt;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:cw_core/enumerable_item.dart';
|
||||
|
||||
class FiatCurrency extends EnumerableItem<String> with Serializable<String> {
|
||||
const FiatCurrency({String symbol, this.countryCode, this.fullName}) : super(title: symbol, raw: symbol);
|
||||
const FiatCurrency({required String symbol, required this.countryCode, required this.fullName}) : super(title: symbol, raw: symbol);
|
||||
|
||||
final String countryCode;
|
||||
final String fullName;
|
||||
@@ -81,7 +81,7 @@ class FiatCurrency extends EnumerableItem<String> with Serializable<String> {
|
||||
FiatCurrency.vef.raw: FiatCurrency.vef
|
||||
};
|
||||
|
||||
static FiatCurrency deserialize({String raw}) => _all[raw];
|
||||
static FiatCurrency deserialize({required String raw}) => _all[raw]!;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => other is FiatCurrency && other.raw == raw;
|
||||
|
||||
@@ -46,7 +46,7 @@ class FioAddressProvider {
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return null;
|
||||
throw Exception('Unexpected response http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
@@ -61,31 +62,45 @@ Future<void> ios_migrate_user_defaults() async {
|
||||
|
||||
//should we provide default btc node key?
|
||||
final activeCurrency = await ios_legacy_helper.getInt('currency');
|
||||
final convertedCurrency = convertFiatLegacy(activeCurrency);
|
||||
|
||||
if (convertedCurrency != null) {
|
||||
await prefs.setString(
|
||||
if (activeCurrency != null) {
|
||||
final convertedCurrency = convertFiatLegacy(activeCurrency);
|
||||
|
||||
if (convertedCurrency != null) {
|
||||
await prefs.setString(
|
||||
'current_fiat_currency', convertedCurrency.serialize());
|
||||
}
|
||||
}
|
||||
|
||||
//translate fee priority
|
||||
final activeFeeTier = await ios_legacy_helper.getInt('saved_fee_priority');
|
||||
await prefs.setInt('current_fee_priority', activeFeeTier);
|
||||
|
||||
if (activeFeeTier != null) {
|
||||
await prefs.setInt('current_fee_priority', activeFeeTier);
|
||||
}
|
||||
|
||||
//translate current balance mode
|
||||
final currentBalanceMode =
|
||||
await ios_legacy_helper.getInt('display_balance_mode');
|
||||
await prefs.setInt('current_balance_display_mode', currentBalanceMode);
|
||||
if (currentBalanceMode != null) {
|
||||
await prefs.setInt('current_balance_display_mode', currentBalanceMode);
|
||||
}
|
||||
|
||||
//translate should save recipient address
|
||||
final shouldSave =
|
||||
await ios_legacy_helper.getBool('should_save_recipient_address');
|
||||
await prefs.setBool('save_recipient_address', shouldSave);
|
||||
|
||||
if (shouldSave != null) {
|
||||
await prefs.setBool('save_recipient_address', shouldSave);
|
||||
}
|
||||
|
||||
//translate biometric
|
||||
final biometricOn =
|
||||
await ios_legacy_helper.getBool('biometric_authentication_on');
|
||||
await prefs.setBool('allow_biometrical_authentication', biometricOn);
|
||||
|
||||
if (biometricOn != null) {
|
||||
await prefs.setBool('allow_biometrical_authentication', biometricOn);
|
||||
}
|
||||
|
||||
//read the current theme as integer, write it back as a bool
|
||||
final currentTheme = prefs.getInt('current-theme');
|
||||
@@ -97,11 +112,17 @@ Future<void> ios_migrate_user_defaults() async {
|
||||
|
||||
//assign the pin length
|
||||
final pinLength = await ios_legacy_helper.getInt('pin-length');
|
||||
await prefs.setInt(PreferencesKey.currentPinLength, pinLength);
|
||||
|
||||
if (pinLength != null) {
|
||||
await prefs.setInt(PreferencesKey.currentPinLength, pinLength);
|
||||
}
|
||||
|
||||
//default value for display list key?
|
||||
final walletName = await ios_legacy_helper.getString('current_wallet_name');
|
||||
await prefs.setString('current_wallet_name', walletName);
|
||||
|
||||
if (walletName != null) {
|
||||
await prefs.setString('current_wallet_name', walletName);
|
||||
}
|
||||
|
||||
await prefs.setInt('current_wallet_type', serializeToInt(WalletType.monero));
|
||||
|
||||
@@ -117,7 +138,13 @@ Future<void> ios_migrate_pin() async {
|
||||
|
||||
final flutterSecureStorage = FlutterSecureStorage();
|
||||
final pinPassword = await flutterSecureStorage.read(
|
||||
key: 'pin_password', iOptions: IOSOptions(syncFlag: "syna"));
|
||||
key: 'pin_password', iOptions: IOSOptions());
|
||||
// No pin
|
||||
if (pinPassword == null) {
|
||||
await prefs.setBool('ios_migration_pin_completed', true);
|
||||
return;
|
||||
}
|
||||
|
||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||
final encodedPassword = encodedPinCode(pin: pinPassword);
|
||||
await flutterSecureStorage.write(key: key, value: encodedPassword);
|
||||
@@ -148,9 +175,9 @@ Future<void> ios_migrate_wallet_passwords() async {
|
||||
final name = item.path.split('/').last;
|
||||
final oldKey = 'wallet_monero_' + name + '_password';
|
||||
final password = await flutterSecureStorage.read(
|
||||
key: oldKey, iOptions: IOSOptions(syncFlag: "syna"));
|
||||
key: oldKey, iOptions: IOSOptions());
|
||||
await keyService.saveWalletPassword(
|
||||
walletName: name, password: password);
|
||||
walletName: name, password: password!);
|
||||
}
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
@@ -197,14 +224,14 @@ FiatCurrency convertFiatLegacy(int raw) {
|
||||
32: 'zar',
|
||||
33: 'vef'
|
||||
};
|
||||
final fiatAsString = _map[raw];
|
||||
final fiatAsString = _map[raw]!;
|
||||
|
||||
return FiatCurrency.deserialize(raw: fiatAsString.toUpperCase());
|
||||
}
|
||||
|
||||
Future<void> android_migrate_hives({Directory appDocDir}) async {
|
||||
Future<void> android_migrate_hives({required Directory appDocDir}) async {
|
||||
final dbDir = Directory('${appDocDir.path}/db');
|
||||
final files = List<File>();
|
||||
final files = <File>[];
|
||||
|
||||
appDocDir.listSync().forEach((FileSystemEntity item) {
|
||||
final ext = item.path.split('.').last;
|
||||
@@ -225,10 +252,10 @@ Future<void> android_migrate_hives({Directory appDocDir}) async {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> android_migrate_wallets({Directory appDocDir}) async {
|
||||
Future<void> android_migrate_wallets({required Directory appDocDir}) async {
|
||||
final walletsDir = Directory('${appDocDir.path}/wallets');
|
||||
final moneroWalletsDir = Directory('${walletsDir.path}/monero');
|
||||
final dirs = List<Directory>();
|
||||
final dirs = <Directory>[];
|
||||
|
||||
appDocDir.listSync().forEach((FileSystemEntity item) {
|
||||
final name = item.path.split('/').last;
|
||||
@@ -292,9 +319,8 @@ Future<void> ios_migrate_wallet_info(Box<WalletInfo> walletsInfoSource) async {
|
||||
'_' +
|
||||
name;
|
||||
final exist = walletsInfoSource.values
|
||||
.firstWhere((el) => el.id == id, orElse: () => null) !=
|
||||
null;
|
||||
|
||||
.firstWhereOrNull((el) => el.id == id) != null;
|
||||
|
||||
if (exist) {
|
||||
return null;
|
||||
}
|
||||
@@ -307,7 +333,8 @@ Future<void> ios_migrate_wallet_info(Box<WalletInfo> walletsInfoSource) async {
|
||||
restoreHeight: 0,
|
||||
date: date,
|
||||
dirPath: item.path,
|
||||
path: '${item.path}/$name');
|
||||
path: '${item.path}/$name',
|
||||
address: '');
|
||||
|
||||
return walletInfo;
|
||||
}
|
||||
@@ -317,8 +344,8 @@ Future<void> ios_migrate_wallet_info(Box<WalletInfo> walletsInfoSource) async {
|
||||
}
|
||||
})
|
||||
.where((el) => el != null)
|
||||
.whereType<WalletInfo>()
|
||||
.toList();
|
||||
print(infoRecords);
|
||||
await walletsInfoSource.addAll(infoRecords);
|
||||
await prefs.setBool('ios_migration_wallet_info_completed', true);
|
||||
} catch (e) {
|
||||
@@ -346,8 +373,8 @@ Future<void> ios_migrate_trades_list(Box<Trade> tradeSource) async {
|
||||
final content = file.readAsBytesSync();
|
||||
final flutterSecureStorage = FlutterSecureStorage();
|
||||
final masterPassword = await flutterSecureStorage.read(
|
||||
key: 'master_password', iOptions: IOSOptions(syncFlag: "syna"));
|
||||
final key = masterPassword.replaceAll('-', '');
|
||||
key: 'master_password', iOptions: IOSOptions());
|
||||
final key = masterPassword!.replaceAll('-', '');
|
||||
final decoded =
|
||||
await ios_legacy_helper.decrypt(content, key: key, salt: secrets.salt);
|
||||
final decodedJson = json.decode(decoded) as List<dynamic>;
|
||||
@@ -362,7 +389,7 @@ Future<void> ios_migrate_trades_list(Box<Trade> tradeSource) async {
|
||||
final from = CryptoCurrency.fromString(fromAsString);
|
||||
final timestamp = dateAsDouble.toInt() * 1000;
|
||||
final date = DateTime.fromMillisecondsSinceEpoch(timestamp);
|
||||
ExchangeProviderDescription provider;
|
||||
ExchangeProviderDescription? provider;
|
||||
|
||||
switch (providerAsString.toLowerCase()) {
|
||||
case 'changenow':
|
||||
@@ -379,7 +406,7 @@ Future<void> ios_migrate_trades_list(Box<Trade> tradeSource) async {
|
||||
}
|
||||
|
||||
return Trade(
|
||||
id: tradeId, provider: provider, from: from, to: to, createdAt: date);
|
||||
id: tradeId, provider: provider!, from: from, to: to, createdAt: date, amount: '');
|
||||
});
|
||||
await tradeSource.addAll(trades);
|
||||
await prefs.setBool('ios_migration_trade_list_completed', true);
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
Future<List<int>> getEncryptionKey(
|
||||
{String forKey, FlutterSecureStorage secureStorage}) async {
|
||||
{required String forKey, required FlutterSecureStorage secureStorage}) async {
|
||||
final stringifiedKey =
|
||||
await secureStorage.read(key: 'transactionDescriptionsBoxKey');
|
||||
List<int> key;
|
||||
|
||||
@@ -7,19 +7,19 @@ const platform =
|
||||
const MethodChannel('com.cakewallet.cakewallet/legacy_wallet_migration');
|
||||
|
||||
Future<String> decrypt(Uint8List bytes,
|
||||
{@required String key, @required String salt}) async =>
|
||||
await platform
|
||||
.invokeMethod('decrypt', {'bytes': bytes, 'key': key, 'salt': salt});
|
||||
{required String key, required String salt}) async =>
|
||||
(await platform
|
||||
.invokeMethod<String>('decrypt', {'bytes': bytes, 'key': key, 'salt': salt}))!;
|
||||
|
||||
Future<dynamic> readUserDefaults(String key, {@required String type}) async =>
|
||||
Future<dynamic> readUserDefaults(String key, {required String type}) async =>
|
||||
await platform
|
||||
.invokeMethod<dynamic>('read_user_defaults', {'key': key, 'type': type});
|
||||
|
||||
Future<String> getString(String key) async =>
|
||||
await readUserDefaults(key, type: 'string') as String;
|
||||
Future<String?> getString(String key) async =>
|
||||
await readUserDefaults(key, type: 'string') as String?;
|
||||
|
||||
Future<bool> getBool(String key) async =>
|
||||
await readUserDefaults(key, type: 'bool') as bool;
|
||||
Future<bool?> getBool(String key) async =>
|
||||
await readUserDefaults(key, type: 'bool') as bool?;
|
||||
|
||||
Future<int> getInt(String key) async =>
|
||||
await readUserDefaults(key, type: 'int') as int;
|
||||
Future<int?> getInt(String key) async =>
|
||||
await readUserDefaults(key, type: 'int') as int?;
|
||||
|
||||
@@ -50,7 +50,7 @@ class LanguageService {
|
||||
}
|
||||
|
||||
static Future<String> localeDetection() async {
|
||||
var locale = await Devicelocale.currentLocale;
|
||||
var locale = await Devicelocale.currentLocale ?? '';
|
||||
locale = Intl.shortLocale(locale);
|
||||
|
||||
return list.keys.contains(locale) ? locale : 'en';
|
||||
|
||||
@@ -15,6 +15,11 @@ Future<void> loadCurrentWallet() async {
|
||||
final typeRaw =
|
||||
getIt.get<SharedPreferences>().getInt(PreferencesKey.currentWalletType) ??
|
||||
0;
|
||||
|
||||
if (name == null) {
|
||||
throw Exception('Incorrect current wallet name: $name');
|
||||
}
|
||||
|
||||
final type = deserializeFromInt(typeRaw);
|
||||
final walletLoadingService = getIt.get<WalletLoadingService>();
|
||||
final wallet = await walletLoadingService.load(type, name);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class MnemonicItem {
|
||||
MnemonicItem({String text}) : _text = text;
|
||||
MnemonicItem({required String text}) : _text = text;
|
||||
|
||||
String get text => _text;
|
||||
String _text;
|
||||
|
||||
+34
-34
@@ -6,68 +6,68 @@ import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
Future<List<Node>> loadDefaultNodes() async {
|
||||
final nodesRaw = await rootBundle.loadString('assets/node_list.yml');
|
||||
final nodes = loadYaml(nodesRaw) as YamlList;
|
||||
final loadedNodes = loadYaml(nodesRaw) as YamlList;
|
||||
final nodes = <Node>[];
|
||||
|
||||
return nodes.map((dynamic raw) {
|
||||
for (final raw in loadedNodes) {
|
||||
if (raw is Map) {
|
||||
final node = Node.fromMap(raw);
|
||||
node?.type = WalletType.monero;
|
||||
|
||||
return node;
|
||||
final node = Node.fromMap(Map<String, Object>.from(raw));
|
||||
node.type = WalletType.monero;
|
||||
nodes.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}).toList();
|
||||
return nodes;
|
||||
}
|
||||
|
||||
Future<List<Node>> loadBitcoinElectrumServerList() async {
|
||||
final serverListRaw =
|
||||
await rootBundle.loadString('assets/bitcoin_electrum_server_list.yml');
|
||||
final serverList = loadYaml(serverListRaw) as YamlList;
|
||||
final loadedServerList = loadYaml(serverListRaw) as YamlList;
|
||||
final serverList = <Node>[];
|
||||
|
||||
return serverList.map((dynamic raw) {
|
||||
if (raw is Map) {
|
||||
final node = Node.fromMap(raw);
|
||||
node?.type = WalletType.bitcoin;
|
||||
|
||||
return node;
|
||||
for (final raw in loadedServerList) {
|
||||
if (raw is Map) {
|
||||
final node = Node.fromMap(Map<String, Object>.from(raw));
|
||||
node.type = WalletType.bitcoin;
|
||||
serverList.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}).toList();
|
||||
return serverList;
|
||||
}
|
||||
|
||||
Future<List<Node>> loadLitecoinElectrumServerList() async {
|
||||
final serverListRaw =
|
||||
await rootBundle.loadString('assets/litecoin_electrum_server_list.yml');
|
||||
final serverList = loadYaml(serverListRaw) as YamlList;
|
||||
final loadedServerList = loadYaml(serverListRaw) as YamlList;
|
||||
final serverList = <Node>[];
|
||||
|
||||
return serverList.map((dynamic raw) {
|
||||
for (final raw in loadedServerList) {
|
||||
if (raw is Map) {
|
||||
final node = Node.fromMap(raw);
|
||||
node?.type = WalletType.litecoin;
|
||||
|
||||
return node;
|
||||
final node = Node.fromMap(Map<String, Object>.from(raw));
|
||||
node.type = WalletType.litecoin;
|
||||
serverList.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}).toList();
|
||||
return serverList;
|
||||
}
|
||||
|
||||
Future<List<Node>> loadDefaultHavenNodes() async {
|
||||
final nodesRaw = await rootBundle.loadString('assets/haven_node_list.yml');
|
||||
final nodes = loadYaml(nodesRaw) as YamlList;
|
||||
final loadedNodes = loadYaml(nodesRaw) as YamlList;
|
||||
final nodes = <Node>[];
|
||||
|
||||
return nodes.map((dynamic raw) {
|
||||
for (final raw in loadedNodes) {
|
||||
if (raw is Map) {
|
||||
final node = Node.fromMap(raw);
|
||||
node?.type = WalletType.haven;
|
||||
|
||||
return node;
|
||||
final node = Node.fromMap(Map<String, Object>.from(raw));
|
||||
node.type = WalletType.haven;
|
||||
nodes.add(node);
|
||||
}
|
||||
|
||||
return null;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
Future resetToDefault(Box<Node> nodeSource) async {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import 'package:basic_utils/basic_utils.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class OpenaliasRecord {
|
||||
OpenaliasRecord({
|
||||
this.address,
|
||||
this.name,
|
||||
this.description,
|
||||
required this.address,
|
||||
required this.name,
|
||||
required this.description,
|
||||
});
|
||||
|
||||
final String name;
|
||||
@@ -24,8 +23,8 @@ class OpenaliasRecord {
|
||||
}
|
||||
|
||||
static Future<OpenaliasRecord> fetchAddressAndName({
|
||||
@required String formattedName,
|
||||
@required String ticker,
|
||||
required String formattedName,
|
||||
required String ticker,
|
||||
}) async {
|
||||
String address = formattedName;
|
||||
String name = formattedName;
|
||||
|
||||
@@ -9,7 +9,7 @@ import 'package:cake_wallet/entities/fio_address_provider.dart';
|
||||
|
||||
class AddressResolver {
|
||||
|
||||
AddressResolver({@required this.yatService, this.walletType});
|
||||
AddressResolver({required this.yatService, required this.walletType});
|
||||
|
||||
final YatService yatService;
|
||||
final WalletType walletType;
|
||||
|
||||
@@ -6,47 +6,42 @@ enum ParseFrom { unstoppableDomains, openAlias, yatRecord, fio, notParsed }
|
||||
|
||||
class ParsedAddress {
|
||||
ParsedAddress({
|
||||
this.addresses,
|
||||
required this.addresses,
|
||||
this.name = '',
|
||||
this.description = '',
|
||||
this.parseFrom = ParseFrom.notParsed,
|
||||
});
|
||||
|
||||
final List<String> addresses;
|
||||
final String name;
|
||||
final String description;
|
||||
final ParseFrom parseFrom;
|
||||
|
||||
factory ParsedAddress.fetchEmojiAddress({
|
||||
@required List<YatRecord> addresses,
|
||||
@required String name,
|
||||
List<YatRecord>? addresses,
|
||||
required String name,
|
||||
}){
|
||||
if (addresses?.isEmpty ?? true) {
|
||||
return ParsedAddress(
|
||||
addresses: [name], parseFrom: ParseFrom.yatRecord);
|
||||
}
|
||||
}
|
||||
return ParsedAddress(
|
||||
addresses: addresses.map((e) => e.address).toList(),
|
||||
addresses: addresses!.map((e) => e.address).toList(),
|
||||
name: name,
|
||||
parseFrom: ParseFrom.yatRecord,
|
||||
);
|
||||
}
|
||||
|
||||
factory ParsedAddress.fetchUnstoppableDomainAddress({
|
||||
@required String address,
|
||||
@required String name,
|
||||
String? address,
|
||||
required String name,
|
||||
}){
|
||||
if (address?.isEmpty ?? true) {
|
||||
if (address?.isEmpty ?? true) {
|
||||
return ParsedAddress(addresses: [name]);
|
||||
}
|
||||
return ParsedAddress(
|
||||
addresses: [address],
|
||||
addresses: [address!],
|
||||
name: name,
|
||||
parseFrom: ParseFrom.unstoppableDomains,
|
||||
);
|
||||
}
|
||||
|
||||
factory ParsedAddress.fetchOpenAliasAddress({@required OpenaliasRecord record, @required String name}){
|
||||
factory ParsedAddress.fetchOpenAliasAddress({OpenaliasRecord? record, required String name}){
|
||||
final formattedName = OpenaliasRecord.formatDomainName(name);
|
||||
if (record == null || record.address.contains(formattedName)) {
|
||||
return ParsedAddress(addresses: [name]);
|
||||
@@ -59,12 +54,16 @@ class ParsedAddress {
|
||||
);
|
||||
}
|
||||
|
||||
factory ParsedAddress.fetchFioAddress({@required String address, @required String name}){
|
||||
|
||||
factory ParsedAddress.fetchFioAddress({required String address, required String name}){
|
||||
return ParsedAddress(
|
||||
addresses: [address],
|
||||
name: name,
|
||||
parseFrom: ParseFrom.fio,
|
||||
);
|
||||
}
|
||||
|
||||
final List<String> addresses;
|
||||
final String name;
|
||||
final String description;
|
||||
final ParseFrom parseFrom;
|
||||
}
|
||||
|
||||
@@ -26,4 +26,6 @@ class PreferencesKey {
|
||||
|
||||
static String moneroWalletUpdateV1Key(String name)
|
||||
=> '${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
|
||||
|
||||
static const exchangeProvidersSelection = 'exchange-providers-selection';
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:barcode_scan/barcode_scan.dart';
|
||||
import 'package:barcode_scan2/barcode_scan2.dart';
|
||||
|
||||
var isQrScannerShown = false;
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ abstract class Record<T extends HiveObject> with Keyable {
|
||||
|
||||
final Box<T> _source;
|
||||
|
||||
StreamSubscription<BoxEvent> _listener;
|
||||
StreamSubscription<BoxEvent>? _listener;
|
||||
|
||||
void fromBind(T original);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ const pinCodePassword = "PIN_CODE_PASSWORD";
|
||||
const backupPassword = "BACKUP_CODE_PASSWORD";
|
||||
|
||||
String generateStoreKeyFor({
|
||||
SecretStoreKey key,
|
||||
required SecretStoreKey key,
|
||||
String walletName = "",
|
||||
}) {
|
||||
var _key = "";
|
||||
|
||||
@@ -4,30 +4,51 @@ part 'template.g.dart';
|
||||
|
||||
@HiveType(typeId: Template.typeId)
|
||||
class Template extends HiveObject {
|
||||
Template({this.name,this.isCurrencySelected, this.address, this.cryptoCurrency, this.amount, this.fiatCurrency, this.amountFiat});
|
||||
Template({
|
||||
required this.nameRaw,
|
||||
required this.isCurrencySelectedRaw,
|
||||
required this.addressRaw,
|
||||
required this.cryptoCurrencyRaw,
|
||||
required this.amountRaw,
|
||||
required this.fiatCurrencyRaw,
|
||||
required this.amountFiatRaw});
|
||||
|
||||
static const typeId = 6;
|
||||
static const boxName = 'Template';
|
||||
|
||||
@HiveField(0)
|
||||
String name;
|
||||
String? nameRaw;
|
||||
|
||||
@HiveField(1)
|
||||
String address;
|
||||
String? addressRaw;
|
||||
|
||||
@HiveField(2)
|
||||
String cryptoCurrency;
|
||||
String? cryptoCurrencyRaw;
|
||||
|
||||
@HiveField(3)
|
||||
String amount;
|
||||
String? amountRaw;
|
||||
|
||||
@HiveField(4)
|
||||
String fiatCurrency;
|
||||
String? fiatCurrencyRaw;
|
||||
|
||||
@HiveField(5)
|
||||
bool isCurrencySelected;
|
||||
bool? isCurrencySelectedRaw;
|
||||
|
||||
@HiveField(6)
|
||||
String amountFiat;
|
||||
String? amountFiatRaw;
|
||||
|
||||
bool get isCurrencySelected => isCurrencySelectedRaw ?? false;
|
||||
|
||||
String get fiatCurrency => fiatCurrencyRaw ?? '';
|
||||
|
||||
String get amountFiat => amountFiatRaw ?? '';
|
||||
|
||||
String get name => nameRaw ?? '';
|
||||
|
||||
String get address => addressRaw ?? '';
|
||||
|
||||
String get cryptoCurrency => cryptoCurrencyRaw ?? '';
|
||||
|
||||
String get amount => amountRaw ?? '';
|
||||
}
|
||||
|
||||
|
||||
@@ -4,20 +4,20 @@ part 'transaction_description.g.dart';
|
||||
|
||||
@HiveType(typeId: TransactionDescription.typeId)
|
||||
class TransactionDescription extends HiveObject {
|
||||
TransactionDescription({this.id, this.recipientAddress, this.transactionNote});
|
||||
TransactionDescription({required this.id, this.recipientAddress, this.transactionNote});
|
||||
|
||||
static const typeId = 2;
|
||||
static const boxName = 'TransactionDescriptions';
|
||||
static const boxKey = 'transactionDescriptionsBoxKey';
|
||||
|
||||
@HiveField(0)
|
||||
@HiveField(0, defaultValue: '')
|
||||
String id;
|
||||
|
||||
@HiveField(1)
|
||||
String recipientAddress;
|
||||
String? recipientAddress;
|
||||
|
||||
@HiveField(2)
|
||||
String transactionNote;
|
||||
String? transactionNote;
|
||||
|
||||
String get note => transactionNote ?? '';
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@ import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
|
||||
abstract class TransactionHistory {
|
||||
TransactionHistory()
|
||||
: transactions = Observable<List<TransactionInfo>>([]);
|
||||
|
||||
Observable<List<TransactionInfo>> transactions;
|
||||
Future<List<TransactionInfo>> getAll();
|
||||
Future update();
|
||||
|
||||
@@ -6,13 +6,13 @@ Future<String> fetchUnstoppableDomainAddress(String domain, String ticker) async
|
||||
var address = '';
|
||||
|
||||
try {
|
||||
address = await channel.invokeMethod(
|
||||
address = await channel.invokeMethod<String>(
|
||||
'getUnstoppableDomainAddress',
|
||||
<String, String> {
|
||||
'domain' : domain,
|
||||
'ticker' : ticker
|
||||
}
|
||||
);
|
||||
) ?? '';
|
||||
} catch (e) {
|
||||
print('Unstoppable domain error: ${e.toString()}');
|
||||
address = '';
|
||||
|
||||
@@ -4,18 +4,23 @@ import 'package:cw_core/monero_amount_format.dart';
|
||||
import 'package:cake_wallet/haven/haven.dart';
|
||||
|
||||
Future<void> updateHavenRate(FiatConversionStore fiatConversionStore) async {
|
||||
final rate = haven.getAssetRate();
|
||||
final base = rate.firstWhere((row) => row.asset == 'XUSD', orElse: () => null);
|
||||
rate.forEach((row) {
|
||||
final cur = CryptoCurrency.fromString(row.asset);
|
||||
final baseRate = moneroAmountToDouble(amount: base.rate);
|
||||
final rowRate = moneroAmountToDouble(amount: row.rate);
|
||||
try {
|
||||
final rate = haven!.getAssetRate();
|
||||
final base = rate.firstWhere((row) => row.asset == 'XUSD');
|
||||
|
||||
if (cur == CryptoCurrency.xusd) {
|
||||
fiatConversionStore.prices[cur] = 1.0;
|
||||
return;
|
||||
}
|
||||
rate.forEach((row) {
|
||||
final cur = CryptoCurrency.fromString(row.asset);
|
||||
final baseRate = moneroAmountToDouble(amount: base.rate);
|
||||
final rowRate = moneroAmountToDouble(amount: row.rate);
|
||||
|
||||
fiatConversionStore.prices[cur] = baseRate / rowRate;
|
||||
});
|
||||
if (cur == CryptoCurrency.xusd) {
|
||||
fiatConversionStore.prices[cur] = 1.0;
|
||||
return;
|
||||
}
|
||||
|
||||
fiatConversionStore.prices[cur] = baseRate / rowRate;
|
||||
});
|
||||
} catch(_) {
|
||||
// FIX-ME: handle exception
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class WalletContact implements ContactBase {
|
||||
WalletContact(this.address, this.name, this.type);
|
||||
//: super(name, address, type);
|
||||
|
||||
@override
|
||||
String address;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
class WalletDescription {
|
||||
WalletDescription({this.name, this.type});
|
||||
WalletDescription({required this.name, required this.type});
|
||||
|
||||
final String name;
|
||||
final WalletType type;
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
class YatRecord {
|
||||
String category;
|
||||
String address;
|
||||
|
||||
YatRecord({
|
||||
this.category,
|
||||
this.address,
|
||||
required this.category,
|
||||
required this.address,
|
||||
});
|
||||
|
||||
YatRecord.fromJson(Map<String, dynamic> json) {
|
||||
address = json['address'] as String;
|
||||
category = json['category'] as String;
|
||||
}
|
||||
YatRecord.fromJson(Map<String, dynamic> json)
|
||||
: address = json['address'] as String,
|
||||
category = json['category'] as String;
|
||||
|
||||
|
||||
String category;
|
||||
String address;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:convert';
|
||||
import 'package:cake_wallet/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:cw_core/crypto_currency.dart';
|
||||
@@ -19,7 +18,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
: _lastUsedRateId = '',
|
||||
super(
|
||||
pairList: CryptoCurrency.all
|
||||
.where((i) => i != CryptoCurrency.xhv)
|
||||
.map((i) => CryptoCurrency.all
|
||||
.where((i) => i != CryptoCurrency.xhv)
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true))
|
||||
.where((c) => c != null))
|
||||
.expand((i) => i)
|
||||
@@ -39,6 +40,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
@override
|
||||
bool get isAvailable => true;
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.changeNow;
|
||||
@@ -51,8 +55,10 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
static String getFlow(bool isFixedRate) => isFixedRate ? 'fixed-rate' : 'standard';
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to,
|
||||
bool isFixedRateMode}) async {
|
||||
Future<Limits> fetchLimits({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final headers = {apiHeaderKey: apiKey};
|
||||
final normalizedFrom = normalizeCryptoCurrency(from);
|
||||
final normalizedTo = normalizeCryptoCurrency(to);
|
||||
@@ -74,29 +80,29 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return null;
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
return Limits(
|
||||
min: responseJSON['minAmount'] as double,
|
||||
max: responseJSON['maxAmount'] as double);
|
||||
min: responseJSON['minAmount'] as double?,
|
||||
max: responseJSON['maxAmount'] as double?);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({TradeRequest request, bool isFixedRateMode}) async {
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final _request = request as ChangeNowRequest;
|
||||
final headers = {
|
||||
apiHeaderKey: apiKey,
|
||||
'Content-Type': 'application/json'};
|
||||
final flow = getFlow(isFixedRateMode);
|
||||
final body = <String, String>{
|
||||
'fromCurrency': normalizeCryptoCurrency(_request.from),
|
||||
'fromCurrency': normalizeCryptoCurrency(_request.from),
|
||||
'toCurrency': normalizeCryptoCurrency(_request.to),
|
||||
'fromNetwork': networkFor(_request.from),
|
||||
'toNetwork': networkFor(_request.to),
|
||||
'fromAmount': _request.fromAmount,
|
||||
'toAmount': _request.toAmount,
|
||||
'fromAmount': _request.fromAmount,
|
||||
'toAmount': _request.toAmount,
|
||||
'address': _request.address,
|
||||
'flow': flow,
|
||||
'refundAddress': _request.refundAddress
|
||||
@@ -117,7 +123,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return null;
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
@@ -140,7 +146,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> findTradeById({@required String id}) async {
|
||||
Future<Trade> findTradeById({required String id}) async {
|
||||
final headers = {apiHeaderKey: apiKey};
|
||||
final params = <String, String>{'id': id};
|
||||
final uri = Uri.https(apiAuthority,findTradeByIdPath, params);
|
||||
@@ -159,7 +165,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return null;
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
@@ -193,11 +199,11 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
{CryptoCurrency from,
|
||||
CryptoCurrency to,
|
||||
double amount,
|
||||
bool isFixedRateMode,
|
||||
bool isReceiveAmount}) async {
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
try {
|
||||
if (amount == 0) {
|
||||
return 0.0;
|
||||
@@ -245,7 +251,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
return CryptoCurrency.btc.title.toLowerCase();
|
||||
default:
|
||||
return currency.tag != null
|
||||
? currency.tag.toLowerCase()
|
||||
? currency.tag!.toLowerCase()
|
||||
: currency.title.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
|
||||
class ChangeNowRequest extends TradeRequest {
|
||||
ChangeNowRequest(
|
||||
{@required this.from,
|
||||
@required this.to,
|
||||
@required this.address,
|
||||
@required this.fromAmount,
|
||||
@required this.toAmount,
|
||||
@required this.refundAddress,
|
||||
@required this.isReverse});
|
||||
{required this.from,
|
||||
required this.to,
|
||||
required this.address,
|
||||
required this.fromAmount,
|
||||
required this.toAmount,
|
||||
required this.refundAddress,
|
||||
required this.isReverse});
|
||||
|
||||
CryptoCurrency from;
|
||||
CryptoCurrency to;
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class ExchangePair {
|
||||
ExchangePair({this.from, this.to, this.reverse = true});
|
||||
ExchangePair({
|
||||
required this.from,
|
||||
required this.to,
|
||||
this.reverse = true});
|
||||
|
||||
final CryptoCurrency from;
|
||||
final CryptoCurrency to;
|
||||
|
||||
@@ -7,21 +7,30 @@ import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
|
||||
abstract class ExchangeProvider {
|
||||
ExchangeProvider({this.pairList});
|
||||
ExchangeProvider({required this.pairList});
|
||||
|
||||
String get title;
|
||||
List<ExchangePair> pairList;
|
||||
ExchangeProviderDescription description;
|
||||
ExchangeProviderDescription get description;
|
||||
bool get isAvailable;
|
||||
bool get isEnabled;
|
||||
|
||||
@override
|
||||
String toString() => title;
|
||||
|
||||
Future<Limits> fetchLimits(
|
||||
{CryptoCurrency from, CryptoCurrency to, bool isFixedRateMode});
|
||||
Future<Trade> createTrade({TradeRequest request, bool isFixedRateMode});
|
||||
Future<Trade> findTradeById({@required String id});
|
||||
Future<double> calculateAmount({CryptoCurrency from, CryptoCurrency to,
|
||||
double amount, bool isFixedRateMode, bool isReceiveAmount});
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode});
|
||||
Future<Trade> createTrade({
|
||||
required TradeRequest request,
|
||||
required bool isFixedRateMode});
|
||||
Future<Trade> findTradeById({required String id});
|
||||
Future<double> calculateAmount({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount});
|
||||
Future<bool> checkIsAvailable();
|
||||
}
|
||||
|
||||
@@ -2,19 +2,29 @@ import 'package:cw_core/enumerable_item.dart';
|
||||
|
||||
class ExchangeProviderDescription extends EnumerableItem<int>
|
||||
with Serializable<int> {
|
||||
const ExchangeProviderDescription({String title, int raw})
|
||||
const ExchangeProviderDescription({
|
||||
required String title,
|
||||
required int raw,
|
||||
required this.image,
|
||||
this.horizontalLogo = false})
|
||||
: super(title: title, raw: raw);
|
||||
|
||||
static const xmrto = ExchangeProviderDescription(title: 'XMR.TO', raw: 0);
|
||||
final bool horizontalLogo;
|
||||
final String image;
|
||||
|
||||
static const xmrto = ExchangeProviderDescription(title: 'XMR.TO', raw: 0, image: 'assets/images/xmrto.png');
|
||||
static const changeNow =
|
||||
ExchangeProviderDescription(title: 'ChangeNOW', raw: 1);
|
||||
ExchangeProviderDescription(title: 'ChangeNOW', raw: 1, image: 'assets/images/changenow.png');
|
||||
static const morphToken =
|
||||
ExchangeProviderDescription(title: 'MorphToken', raw: 2);
|
||||
ExchangeProviderDescription(title: 'MorphToken', raw: 2, image: 'assets/images/morph.png');
|
||||
|
||||
static const sideShift =
|
||||
ExchangeProviderDescription(title: 'SideShift', raw: 3);
|
||||
ExchangeProviderDescription(title: 'SideShift', raw: 3, image: 'assets/images/sideshift.png');
|
||||
|
||||
static ExchangeProviderDescription deserialize({int raw}) {
|
||||
static const simpleSwap =
|
||||
ExchangeProviderDescription(title: 'SimpleSwap', raw: 4, image: 'assets/images/simpleSwap.png');
|
||||
|
||||
static ExchangeProviderDescription deserialize({required int raw}) {
|
||||
switch (raw) {
|
||||
case 0:
|
||||
return xmrto;
|
||||
@@ -24,8 +34,10 @@ class ExchangeProviderDescription extends EnumerableItem<int>
|
||||
return morphToken;
|
||||
case 3:
|
||||
return sideShift;
|
||||
case 4:
|
||||
return simpleSwap;
|
||||
default:
|
||||
return null;
|
||||
throw Exception('Unexpected token: $raw for ExchangeProviderDescription deserialize');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,32 +5,44 @@ part 'exchange_template.g.dart';
|
||||
@HiveType(typeId: ExchangeTemplate.typeId)
|
||||
class ExchangeTemplate extends HiveObject {
|
||||
ExchangeTemplate({
|
||||
this.amount,
|
||||
this.depositCurrency,
|
||||
this.receiveCurrency,
|
||||
this.provider,
|
||||
this.depositAddress,
|
||||
this.receiveAddress
|
||||
required this.amountRaw,
|
||||
required this.depositCurrencyRaw,
|
||||
required this.receiveCurrencyRaw,
|
||||
required this.providerRaw,
|
||||
required this.depositAddressRaw,
|
||||
required this.receiveAddressRaw
|
||||
});
|
||||
|
||||
static const typeId = 7;
|
||||
static const boxName = 'ExchangeTemplate';
|
||||
|
||||
@HiveField(0)
|
||||
String amount;
|
||||
String? amountRaw;
|
||||
|
||||
@HiveField(1)
|
||||
String depositCurrency;
|
||||
String? depositCurrencyRaw;
|
||||
|
||||
@HiveField(2)
|
||||
String receiveCurrency;
|
||||
String? receiveCurrencyRaw;
|
||||
|
||||
@HiveField(3)
|
||||
String provider;
|
||||
String? providerRaw;
|
||||
|
||||
@HiveField(4)
|
||||
String depositAddress;
|
||||
String? depositAddressRaw;
|
||||
|
||||
@HiveField(5)
|
||||
String receiveAddress;
|
||||
String? receiveAddressRaw;
|
||||
|
||||
String get amount => amountRaw ?? '';
|
||||
|
||||
String get depositCurrency => depositCurrencyRaw ?? '';
|
||||
|
||||
String get receiveCurrency => receiveCurrencyRaw ?? '';
|
||||
|
||||
String get provider => providerRaw ?? '';
|
||||
|
||||
String get depositAddress => depositAddressRaw ?? '';
|
||||
|
||||
String get receiveAddress => receiveAddressRaw ?? '';
|
||||
}
|
||||
@@ -8,13 +8,13 @@ class ExchangeTradeStateInitial extends ExchangeTradeState {}
|
||||
class TradeIsCreating extends ExchangeTradeState {}
|
||||
|
||||
class TradeIsCreatedSuccessfully extends ExchangeTradeState {
|
||||
TradeIsCreatedSuccessfully({@required this.trade});
|
||||
TradeIsCreatedSuccessfully({required this.trade});
|
||||
|
||||
final Trade trade;
|
||||
}
|
||||
|
||||
class TradeIsCreatedFailure extends ExchangeTradeState {
|
||||
TradeIsCreatedFailure({@required this.title, @required this.error});
|
||||
TradeIsCreatedFailure({required this.title, required this.error});
|
||||
|
||||
final String title;
|
||||
final String error;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Limits {
|
||||
const Limits({this.min, this.max});
|
||||
|
||||
final double min;
|
||||
final double max;
|
||||
final double? min;
|
||||
final double? max;
|
||||
}
|
||||
@@ -8,13 +8,13 @@ class LimitsInitialState extends LimitsState {}
|
||||
class LimitsIsLoading extends LimitsState {}
|
||||
|
||||
class LimitsLoadedSuccessfully extends LimitsState {
|
||||
LimitsLoadedSuccessfully({@required this.limits});
|
||||
LimitsLoadedSuccessfully({required this.limits});
|
||||
|
||||
final Limits limits;
|
||||
}
|
||||
|
||||
class LimitsLoadedFailure extends LimitsState {
|
||||
LimitsLoadedFailure({@required this.error});
|
||||
LimitsLoadedFailure({required this.error});
|
||||
|
||||
final String error;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'dart:convert';
|
||||
import 'package:cake_wallet/core/amount_converter.dart';
|
||||
import 'package:cw_core/amount_converter.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
@@ -16,7 +16,7 @@ import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exeption.dart';
|
||||
|
||||
class MorphTokenExchangeProvider extends ExchangeProvider {
|
||||
MorphTokenExchangeProvider({@required this.trades})
|
||||
MorphTokenExchangeProvider({required this.trades})
|
||||
: super(pairList: [
|
||||
ExchangePair(from: CryptoCurrency.xmr, to: CryptoCurrency.eth),
|
||||
ExchangePair(from: CryptoCurrency.xmr, to: CryptoCurrency.bch),
|
||||
@@ -63,6 +63,9 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
|
||||
@override
|
||||
bool get isAvailable => true;
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.morphToken;
|
||||
@@ -71,8 +74,12 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
|
||||
Future<bool> checkIsAvailable() async => true;
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to, bool isFixedRateMode}) async {
|
||||
Future<Limits> fetchLimits({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final url = apiUri + _limitsURISuffix;
|
||||
final uri = Uri.parse(url);
|
||||
final headers = {'Content-type': 'application/json'};
|
||||
final body = json.encode({
|
||||
"input": {"asset": from.toString()},
|
||||
@@ -80,11 +87,11 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
|
||||
{"asset": to.toString(), "weight": weight}
|
||||
]
|
||||
});
|
||||
final response = await post(url, headers: headers, body: body);
|
||||
final response = await post(uri, headers: headers, body: body);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
final min = responseJSON['input']['limits']['min'] as int;
|
||||
int max;
|
||||
int max = 0;
|
||||
double ethMax;
|
||||
|
||||
if (from == CryptoCurrency.eth) {
|
||||
@@ -93,14 +100,16 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
|
||||
max = responseJSON['input']['limits']['max'] as int;
|
||||
}
|
||||
|
||||
double minFormatted = AmountConverter.amountIntToDouble(from, min);
|
||||
double maxFormatted = AmountConverter.amountIntToDouble(from, max);
|
||||
final minFormatted = AmountConverter.amountIntToDouble(from, min);
|
||||
final maxFormatted = AmountConverter.amountIntToDouble(from, max);
|
||||
|
||||
return Limits(min: minFormatted, max: maxFormatted);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({TradeRequest request, bool isFixedRateMode}) async {
|
||||
Future<Trade> createTrade({
|
||||
required TradeRequest request,
|
||||
required bool isFixedRateMode}) async {
|
||||
const url = apiUri + _morphURISuffix;
|
||||
final _request = request as MorphTokenRequest;
|
||||
final body = {
|
||||
@@ -117,8 +126,8 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
|
||||
],
|
||||
"tag": "cakewallet"
|
||||
};
|
||||
|
||||
final response = await post(url,
|
||||
final uri = Uri.parse(url);
|
||||
final response = await post(uri,
|
||||
headers: {'Content-Type': 'application/json'}, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
@@ -146,9 +155,10 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> findTradeById({@required String id}) async {
|
||||
Future<Trade> findTradeById({required String id}) async {
|
||||
final url = apiUri + _morphURISuffix + '/' + id;
|
||||
final response = await get(url);
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode == 400) {
|
||||
@@ -191,17 +201,21 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
{CryptoCurrency from, CryptoCurrency to, double amount, bool isFixedRateMode,
|
||||
bool isReceiveAmount}) async {
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
final url = apiUri + _ratesURISuffix;
|
||||
final response = await get(url);
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
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) {
|
||||
} catch (_) {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
|
||||
class MorphTokenRequest extends TradeRequest {
|
||||
MorphTokenRequest(
|
||||
{@required this.from,
|
||||
@required this.to,
|
||||
@required this.address,
|
||||
@required this.amount,
|
||||
@required this.refundAddress});
|
||||
{required this.from,
|
||||
required this.to,
|
||||
required this.address,
|
||||
required this.amount,
|
||||
required this.refundAddress});
|
||||
|
||||
CryptoCurrency from;
|
||||
CryptoCurrency to;
|
||||
|
||||
@@ -16,23 +16,43 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
SideShiftExchangeProvider()
|
||||
: super(
|
||||
pairList: CryptoCurrency.all
|
||||
.map((i) => CryptoCurrency.all
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true))
|
||||
.where((c) => c != null))
|
||||
.expand((i) => i)
|
||||
.toList());
|
||||
SideShiftExchangeProvider() : super(pairList: _supportedPairs());
|
||||
|
||||
static const apiKey = secrets.sideShiftApiKey;
|
||||
static const affiliateId = secrets.sideShiftAffiliateId;
|
||||
static const apiBaseUrl = 'https://sideshift.ai/api';
|
||||
static const rangePath = '/v1/pairs';
|
||||
static const orderPath = '/v1/orders';
|
||||
static const quotePath = '/v1/quotes';
|
||||
static const permissionPath = '/v1/permissions';
|
||||
static const apiHeaderKey = 'x-sideshift-secret';
|
||||
|
||||
static const List<CryptoCurrency> _notSupported = [
|
||||
CryptoCurrency.xhv,
|
||||
CryptoCurrency.dcr,
|
||||
CryptoCurrency.husd,
|
||||
CryptoCurrency.kmd,
|
||||
CryptoCurrency.mkr,
|
||||
CryptoCurrency.near,
|
||||
CryptoCurrency.oxt,
|
||||
CryptoCurrency.paxg,
|
||||
CryptoCurrency.pivx,
|
||||
CryptoCurrency.rune,
|
||||
CryptoCurrency.rvn,
|
||||
CryptoCurrency.scrt,
|
||||
CryptoCurrency.stx,
|
||||
];
|
||||
|
||||
static List<ExchangePair> _supportedPairs() {
|
||||
final supportedCurrencies = CryptoCurrency.all
|
||||
.where((element) => !_notSupported.contains(element))
|
||||
.toList();
|
||||
|
||||
return supportedCurrencies
|
||||
.map((i) => supportedCurrencies
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true))
|
||||
.where((c) => c != null))
|
||||
.expand((i) => i)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
@@ -40,20 +60,21 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
{CryptoCurrency from,
|
||||
CryptoCurrency to,
|
||||
double amount,
|
||||
bool isFixedRateMode,
|
||||
bool isReceiveAmount}) async {
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
try {
|
||||
if (amount == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
final fromCurrency = normalizeCryptoCurrency(from);
|
||||
final toCurrency = normalizeCryptoCurrency(to);
|
||||
final fromCurrency = _normalizeCryptoCurrency(from);
|
||||
final toCurrency = _normalizeCryptoCurrency(to);
|
||||
final url =
|
||||
apiBaseUrl + rangePath + '/' + fromCurrency + '/' + toCurrency;
|
||||
final response = await get(url);
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final rate = double.parse(responseJSON['rate'] as String);
|
||||
final max = double.parse(responseJSON['max'] as String);
|
||||
@@ -71,7 +92,8 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
@override
|
||||
Future<bool> checkIsAvailable() async {
|
||||
const url = apiBaseUrl + permissionPath;
|
||||
final response = await get(url);
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode == 500) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
@@ -92,11 +114,11 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade(
|
||||
{TradeRequest request, bool isFixedRateMode}) async {
|
||||
{required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final _request = request as SideShiftRequest;
|
||||
final quoteId = await _createQuote(_request);
|
||||
final url = apiBaseUrl + orderPath;
|
||||
final headers = {apiHeaderKey: apiKey, 'Content-Type': 'application/json'};
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
final body = {
|
||||
'type': 'fixed',
|
||||
'quoteId': quoteId,
|
||||
@@ -104,7 +126,8 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
'settleAddress': _request.settleAddress,
|
||||
'refundAddress': _request.refundAddress
|
||||
};
|
||||
final response = await post(url, headers: headers, body: json.encode(body));
|
||||
final uri = Uri.parse(url);
|
||||
final response = await post(uri, headers: headers, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 201) {
|
||||
if (response.statusCode == 400) {
|
||||
@@ -137,16 +160,17 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
|
||||
Future<String> _createQuote(SideShiftRequest request) async {
|
||||
final url = apiBaseUrl + quotePath;
|
||||
final headers = {apiHeaderKey: apiKey, 'Content-Type': 'application/json'};
|
||||
final depositMethod = normalizeCryptoCurrency(request.depositMethod);
|
||||
final settleMethod = normalizeCryptoCurrency(request.settleMethod);
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
final depositMethod = _normalizeCryptoCurrency(request.depositMethod);
|
||||
final settleMethod = _normalizeCryptoCurrency(request.settleMethod);
|
||||
final body = {
|
||||
'depositMethod': depositMethod,
|
||||
'settleMethod': settleMethod,
|
||||
'affiliateId': affiliateId,
|
||||
'depositAmount': request.depositAmount,
|
||||
};
|
||||
final response = await post(url, headers: headers, body: json.encode(body));
|
||||
final uri = Uri.parse(url);
|
||||
final response = await post(uri, headers: headers, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 201) {
|
||||
if (response.statusCode == 400) {
|
||||
@@ -167,11 +191,14 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits(
|
||||
{CryptoCurrency from, CryptoCurrency to, bool isFixedRateMode}) async {
|
||||
final fromCurrency = normalizeCryptoCurrency(from);
|
||||
final toCurrency = normalizeCryptoCurrency(to);
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final fromCurrency = _normalizeCryptoCurrency(from);
|
||||
final toCurrency = _normalizeCryptoCurrency(to);
|
||||
final url = apiBaseUrl + rangePath + '/' + fromCurrency + '/' + toCurrency;
|
||||
final response = await get(url);
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode == 500) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
@@ -181,20 +208,21 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return null;
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final min = double.parse(responseJSON['min'] as String);
|
||||
final max = double.parse(responseJSON['max'] as String);
|
||||
final min = double.tryParse(responseJSON['min'] as String? ?? '');
|
||||
final max = double.tryParse(responseJSON['max'] as String? ?? '');
|
||||
|
||||
return Limits(min: min, max: max);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> findTradeById({@required String id}) async {
|
||||
Future<Trade> findTradeById({required String id}) async {
|
||||
final url = apiBaseUrl + orderPath + '/' + id;
|
||||
final response = await get(url);
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode == 404) {
|
||||
throw TradeNotFoundException(id, provider: description);
|
||||
@@ -209,7 +237,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return null;
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
@@ -219,8 +247,8 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
final to = CryptoCurrency.fromString(toCurrency);
|
||||
final inputAddress = responseJSON['depositAddress']['address'] as String;
|
||||
final expectedSendAmount = responseJSON['depositAmount'].toString();
|
||||
final deposits = responseJSON['deposits'] as List;
|
||||
TradeState state;
|
||||
final deposits = responseJSON['deposits'] as List?;
|
||||
TradeState? state;
|
||||
|
||||
if (deposits != null && deposits.isNotEmpty) {
|
||||
final status = deposits[0]['status'] as String;
|
||||
@@ -246,19 +274,30 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
@override
|
||||
bool get isAvailable => true;
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
String get title => 'SideShift';
|
||||
|
||||
static String normalizeCryptoCurrency(CryptoCurrency currency) {
|
||||
static String _normalizeCryptoCurrency(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
case CryptoCurrency.zaddr:
|
||||
return 'zaddr';
|
||||
case CryptoCurrency.zec:
|
||||
return 'zec';
|
||||
case CryptoCurrency.bnb:
|
||||
return currency.tag.toLowerCase();
|
||||
return currency.tag!.toLowerCase();
|
||||
case CryptoCurrency.usdterc20:
|
||||
return 'usdtErc20';
|
||||
case CryptoCurrency.usdttrc20:
|
||||
return 'usdtTrc20';
|
||||
case CryptoCurrency.usdcpoly:
|
||||
return 'usdcpolygon';
|
||||
case CryptoCurrency.usdcsol:
|
||||
return 'usdcsol';
|
||||
case CryptoCurrency.maticpoly:
|
||||
return 'polygon';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
|
||||
@@ -2,16 +2,16 @@ import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class SideShiftRequest extends TradeRequest {
|
||||
SideShiftRequest(
|
||||
{required this.depositMethod,
|
||||
required this.settleMethod,
|
||||
required this.depositAmount,
|
||||
required this.settleAddress,
|
||||
required this.refundAddress});
|
||||
|
||||
final CryptoCurrency depositMethod;
|
||||
final CryptoCurrency settleMethod;
|
||||
final String depositAmount;
|
||||
final String settleAddress;
|
||||
final String refundAddress;
|
||||
|
||||
SideShiftRequest(
|
||||
{this.depositMethod,
|
||||
this.settleMethod,
|
||||
this.depositAmount,
|
||||
this.settleAddress,
|
||||
this.refundAddress,});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
import 'dart:convert';
|
||||
import 'package:cake_wallet/exchange/exchange_pair.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exeption.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class SimpleSwapExchangeProvider extends ExchangeProvider {
|
||||
SimpleSwapExchangeProvider()
|
||||
: super(
|
||||
pairList: CryptoCurrency.all
|
||||
.where((i) => i != CryptoCurrency.zaddr)
|
||||
.map((i) => CryptoCurrency.all
|
||||
.where((i) => i != CryptoCurrency.zaddr)
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true))
|
||||
.where((c) => c != null))
|
||||
.expand((i) => i)
|
||||
.toList());
|
||||
|
||||
static const apiAuthority = 'api.simpleswap.io';
|
||||
static const getEstimatePath = '/v1/get_estimated';
|
||||
static const rangePath = '/v1/get_ranges';
|
||||
static const getExchangePath = '/v1/get_exchange';
|
||||
static const createExchangePath = '/v1/create_exchange';
|
||||
static const apiKey = secrets.simpleSwapApiKey;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.simpleSwap;
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
try {
|
||||
if (amount == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
final fromCurrency = _normalizeCryptoCurrency(from);
|
||||
final toCurrency = _normalizeCryptoCurrency(to);
|
||||
final params = <String, String>{
|
||||
'api_key': apiKey,
|
||||
'currency_from': fromCurrency,
|
||||
'currency_to': toCurrency,
|
||||
'amount': amount.toString(),
|
||||
'fixed': isFixedRateMode.toString()
|
||||
};
|
||||
final uri = Uri.https(apiAuthority, getEstimatePath, params);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.body == null || response.body == "null") return 0.00;
|
||||
final data = json.decode(response.body) as String;
|
||||
return double.parse(data);
|
||||
} catch (_) {
|
||||
return 0.00;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> checkIsAvailable() async {
|
||||
final uri = Uri.https(apiAuthority, getEstimatePath, <String, String>{'api_key': apiKey});
|
||||
final response = await get(uri);
|
||||
|
||||
return !(response.statusCode == 403);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final _request = request as SimpleSwapRequest;
|
||||
final headers = {
|
||||
'Content-Type': 'application/json'};
|
||||
final params = <String, String>{
|
||||
'api_key': apiKey,
|
||||
};
|
||||
final body = <String, dynamic>{
|
||||
"currency_from": _normalizeCryptoCurrency(_request.from),
|
||||
"currency_to": _normalizeCryptoCurrency(_request.to),
|
||||
"amount": _request.amount,
|
||||
"fixed": isFixedRateMode,
|
||||
"user_refund_address": _request.refundAddress,
|
||||
"address_to": _request.address
|
||||
};
|
||||
final uri = Uri.https(apiAuthority, createExchangePath, params);
|
||||
|
||||
final response = await post(uri, headers: headers, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 200 && response.statusCode != 201) {
|
||||
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['address_from'] as String;
|
||||
final settleAddress = responseJSON['user_refund_address'] as String;
|
||||
final extraId = responseJSON['extra_id_from'] as String?;
|
||||
return Trade(
|
||||
id: id,
|
||||
provider: description,
|
||||
from: _request.from,
|
||||
to: _request.to,
|
||||
inputAddress: inputAddress,
|
||||
refundAddress: settleAddress,
|
||||
extraId: extraId,
|
||||
state: TradeState.created,
|
||||
amount: _request.amount,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final fromCurrency = _normalizeCryptoCurrency(from);
|
||||
final toCurrency = _normalizeCryptoCurrency(to);
|
||||
final params = <String, dynamic>{
|
||||
'api_key': apiKey,
|
||||
'fixed': isFixedRateMode.toString(),
|
||||
'currency_from': fromCurrency,
|
||||
'currency_to': toCurrency,
|
||||
};
|
||||
final uri = Uri.https(apiAuthority, rangePath, params);
|
||||
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode == 500) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['message'] as String;
|
||||
|
||||
throw Exception('$error');
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final min = double.tryParse(responseJSON['min'] as String? ?? '');
|
||||
final max = double.tryParse(responseJSON['max'] as String? ?? '');
|
||||
|
||||
return Limits(min: min, max: max);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> findTradeById({required String id}) async {
|
||||
final params = {'api_key': apiKey, 'id': id};
|
||||
final uri = Uri.https(apiAuthority, getExchangePath, params);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode == 404) {
|
||||
throw TradeNotFoundException(id, provider: description);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final fromCurrency = responseJSON['currency_from'] as String;
|
||||
final from = CryptoCurrency.fromString(fromCurrency);
|
||||
final toCurrency = responseJSON['currency_to'] as String;
|
||||
final to = CryptoCurrency.fromString(toCurrency);
|
||||
final inputAddress = responseJSON['address_from'] as String;
|
||||
final expectedSendAmount = responseJSON['expected_amount'].toString();
|
||||
final extraId = responseJSON['extra_id_from'] as String?;
|
||||
final status = responseJSON['status'] as String;
|
||||
final state = TradeState.deserialize(raw: status);
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: from,
|
||||
to: to,
|
||||
extraId: extraId,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: expectedSendAmount,
|
||||
state: state,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isAvailable => true;
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
String get title => 'SimpleSwap';
|
||||
|
||||
static String _normalizeCryptoCurrency(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
case CryptoCurrency.zaddr:
|
||||
return 'zec';
|
||||
case CryptoCurrency.zec:
|
||||
return 'zec';
|
||||
case CryptoCurrency.bnb:
|
||||
return currency.tag!.toLowerCase();
|
||||
case CryptoCurrency.usdterc20:
|
||||
return 'usdterc20';
|
||||
case CryptoCurrency.usdttrc20:
|
||||
return 'usdttrc20';
|
||||
case CryptoCurrency.usdcpoly:
|
||||
return 'usdcpoly';
|
||||
case CryptoCurrency.usdcsol:
|
||||
return 'usdcspl';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SimpleSwapRequest extends TradeRequest {
|
||||
SimpleSwapRequest({
|
||||
required this.from,
|
||||
required this.to,
|
||||
required this.address,
|
||||
required this.amount,
|
||||
required this.refundAddress,
|
||||
this.toAmount = ''
|
||||
});
|
||||
|
||||
CryptoCurrency from;
|
||||
CryptoCurrency to;
|
||||
String address;
|
||||
String amount;
|
||||
String toAmount;
|
||||
String refundAddress;
|
||||
}
|
||||
+39
-30
@@ -9,77 +9,86 @@ part 'trade.g.dart';
|
||||
@HiveType(typeId: Trade.typeId)
|
||||
class Trade extends HiveObject {
|
||||
Trade(
|
||||
{this.id,
|
||||
ExchangeProviderDescription provider,
|
||||
CryptoCurrency from,
|
||||
CryptoCurrency to,
|
||||
TradeState state,
|
||||
{required this.id,
|
||||
required this.amount,
|
||||
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;
|
||||
this.walletId}) {
|
||||
if (provider != null) {
|
||||
providerRaw = provider.raw;
|
||||
}
|
||||
if (from != null) {
|
||||
fromRaw = from.raw;
|
||||
}
|
||||
if (to != null) {
|
||||
toRaw = to.raw;
|
||||
}
|
||||
if (state != null) {
|
||||
stateRaw = state.raw;
|
||||
}
|
||||
}
|
||||
|
||||
static const typeId = 3;
|
||||
static const boxName = 'Trades';
|
||||
static const boxKey = 'tradesBoxKey';
|
||||
|
||||
@HiveField(0)
|
||||
@HiveField(0, defaultValue: '')
|
||||
String id;
|
||||
|
||||
@HiveField(1)
|
||||
int providerRaw;
|
||||
@HiveField(1, defaultValue: 0)
|
||||
late int providerRaw;
|
||||
|
||||
ExchangeProviderDescription get provider =>
|
||||
ExchangeProviderDescription.deserialize(raw: providerRaw);
|
||||
|
||||
@HiveField(2)
|
||||
int fromRaw;
|
||||
@HiveField(2, defaultValue: 0)
|
||||
late int fromRaw;
|
||||
|
||||
CryptoCurrency get from => CryptoCurrency.deserialize(raw: fromRaw);
|
||||
|
||||
@HiveField(3)
|
||||
int toRaw;
|
||||
@HiveField(3, defaultValue: 0)
|
||||
late int toRaw;
|
||||
|
||||
CryptoCurrency get to => CryptoCurrency.deserialize(raw: toRaw);
|
||||
|
||||
@HiveField(4)
|
||||
String stateRaw;
|
||||
@HiveField(4, defaultValue: '')
|
||||
late String stateRaw;
|
||||
|
||||
TradeState get state => TradeState.deserialize(raw: stateRaw);
|
||||
|
||||
@HiveField(5)
|
||||
DateTime createdAt;
|
||||
DateTime? createdAt;
|
||||
|
||||
@HiveField(6)
|
||||
DateTime expiredAt;
|
||||
DateTime? expiredAt;
|
||||
|
||||
@HiveField(7)
|
||||
@HiveField(7, defaultValue: '')
|
||||
String amount;
|
||||
|
||||
@HiveField(8)
|
||||
String inputAddress;
|
||||
String? inputAddress;
|
||||
|
||||
@HiveField(9)
|
||||
String extraId;
|
||||
String? extraId;
|
||||
|
||||
@HiveField(10)
|
||||
String outputTransaction;
|
||||
String? outputTransaction;
|
||||
|
||||
@HiveField(11)
|
||||
String refundAddress;
|
||||
String? refundAddress;
|
||||
|
||||
@HiveField(12)
|
||||
String walletId;
|
||||
String? walletId;
|
||||
|
||||
static Trade fromMap(Map map) {
|
||||
static Trade fromMap(Map<String, Object?> map) {
|
||||
return Trade(
|
||||
id: map['id'] as String,
|
||||
provider: ExchangeProviderDescription.deserialize(
|
||||
@@ -99,7 +108,7 @@ class Trade extends HiveObject {
|
||||
'provider': provider.serialize(),
|
||||
'input': from.serialize(),
|
||||
'output': to.serialize(),
|
||||
'date': createdAt != null ? createdAt.millisecondsSinceEpoch : null,
|
||||
'date': createdAt != null ? createdAt!.millisecondsSinceEpoch : null,
|
||||
'amount': amount,
|
||||
'wallet_id': walletId
|
||||
};
|
||||
|
||||
@@ -4,14 +4,14 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||
class TradeNotFoundException implements Exception {
|
||||
TradeNotFoundException(this.tradeId, {this.provider, this.description = ''});
|
||||
|
||||
String tradeId;
|
||||
ExchangeProviderDescription provider;
|
||||
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_id_not_found(tradeId!, provider!.title)
|
||||
: S.current.trade_not_found;
|
||||
text += ' $description';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:cw_core/enumerable_item.dart';
|
||||
|
||||
class TradeState extends EnumerableItem<String> with Serializable<String> {
|
||||
const TradeState({@required String raw, @required String title})
|
||||
const TradeState({required String raw, required String title})
|
||||
: super(raw: raw, title: title);
|
||||
|
||||
@override
|
||||
@@ -35,7 +35,7 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
|
||||
static const completed = TradeState(raw: 'completed', title: 'Completed');
|
||||
static const settling = TradeState(raw: 'settling', title: 'Settlement in progress');
|
||||
static const settled = TradeState(raw: 'settled', title: 'Settlement completed');
|
||||
static TradeState deserialize({String raw}) {
|
||||
static TradeState deserialize({required String raw}) {
|
||||
switch (raw) {
|
||||
case 'pending':
|
||||
return pending;
|
||||
@@ -78,7 +78,7 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
|
||||
case 'completed':
|
||||
return completed;
|
||||
default:
|
||||
return null;
|
||||
throw Exception('Unexpected token: $raw in TradeState deserialize');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,8 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||
|
||||
static Future<bool> _checkIsAvailable() async {
|
||||
const url = originalApiUri + _orderParameterUriSuffix;
|
||||
final response = await get(url, headers: _headers);
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri, headers: _headers);
|
||||
return !(response.statusCode == 403);
|
||||
}
|
||||
|
||||
@@ -44,6 +45,9 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||
@override
|
||||
bool get isAvailable => _isAvailable;
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.xmrto;
|
||||
@@ -58,9 +62,13 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to, bool isFixedRateMode}) async {
|
||||
Future<Limits> fetchLimits({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final url = originalApiUri + _orderParameterUriSuffix;
|
||||
final response = await get(url);
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
final correction = 0.001;
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
@@ -91,16 +99,14 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({TradeRequest request, bool isFixedRateMode}) async {
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final _request = request as XMRTOTradeRequest;
|
||||
final url = originalApiUri + _orderCreateUriSuffix;
|
||||
final _amount =
|
||||
_request.isBTCRequest ? _request.receiveAmount : _request.amount;
|
||||
|
||||
final _amountCurrency = _request.isBTCRequest
|
||||
? _request.to.toString()
|
||||
: _request.from.toString();
|
||||
|
||||
final pattern = '^([0-9]+([.\,][0-9]{0,8})?|[.\,][0-9]{1,8})\$';
|
||||
final isValid = RegExp(pattern).hasMatch(_amount);
|
||||
|
||||
@@ -112,10 +118,10 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||
final body = {
|
||||
'amount': _amount,
|
||||
'amount_currency': _amountCurrency,
|
||||
'btc_dest_address': _request.address
|
||||
};
|
||||
'btc_dest_address': _request.address};
|
||||
final uri = Uri.parse(url);
|
||||
final response =
|
||||
await post(url, headers: _headers, body: json.encode(body));
|
||||
await post(uri, headers: _headers, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 201) {
|
||||
if (response.statusCode == 400) {
|
||||
@@ -142,11 +148,12 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> findTradeById({@required String id}) async {
|
||||
Future<Trade> findTradeById({required String id}) async {
|
||||
final url = originalApiUri + _orderStatusUriSuffix;
|
||||
final uri = Uri.parse(url);
|
||||
final body = {'uuid': id};
|
||||
final response =
|
||||
await post(url, headers: _headers, body: json.encode(body));
|
||||
await post(uri, headers: _headers, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode == 400) {
|
||||
@@ -185,16 +192,16 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
{CryptoCurrency from,
|
||||
CryptoCurrency to,
|
||||
double amount,
|
||||
bool isFixedRateMode,
|
||||
bool isReceiveAmount}) async {
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
if (from != CryptoCurrency.xmr && to != CryptoCurrency.btc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_rate == null || _rate == 0) {
|
||||
if (_rate == 0) {
|
||||
_rate = await _fetchRates();
|
||||
}
|
||||
|
||||
@@ -210,7 +217,8 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||
Future<double> _fetchRates() async {
|
||||
try {
|
||||
final url = originalApiUri + _orderParameterUriSuffix;
|
||||
final response = await get(url, headers: _headers);
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri, headers: _headers);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final price = double.parse(responseJSON['price'] as String);
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
|
||||
class XMRTOTradeRequest extends TradeRequest {
|
||||
XMRTOTradeRequest(
|
||||
{@required this.from,
|
||||
@required this.to,
|
||||
@required this.amount,
|
||||
@required this.receiveAmount,
|
||||
@required this.address,
|
||||
@required this.refundAddress,
|
||||
@required this.isBTCRequest});
|
||||
{required this.from,
|
||||
required this.to,
|
||||
required this.amount,
|
||||
required this.receiveAmount,
|
||||
required this.address,
|
||||
required this.refundAddress,
|
||||
required this.isBTCRequest});
|
||||
|
||||
final CryptoCurrency from;
|
||||
final CryptoCurrency to;
|
||||
|
||||
+67
-30
@@ -2,7 +2,7 @@ part of 'haven.dart';
|
||||
|
||||
class CWHavenAccountList extends HavenAccountList {
|
||||
CWHavenAccountList(this._wallet);
|
||||
Object _wallet;
|
||||
final Object _wallet;
|
||||
|
||||
@override
|
||||
@computed
|
||||
@@ -37,13 +37,13 @@ class CWHavenAccountList extends HavenAccountList {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> addAccount(Object wallet, {String label}) async {
|
||||
Future<void> addAccount(Object wallet, {required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.accountList.addAccount(label: label);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setLabelAccount(Object wallet, {int accountIndex, String label}) async {
|
||||
Future<void> setLabelAccount(Object wallet, {required int accountIndex, required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.accountList
|
||||
.setLabelAccount(
|
||||
@@ -54,7 +54,7 @@ class CWHavenAccountList extends HavenAccountList {
|
||||
|
||||
class CWHavenSubaddressList extends MoneroSubaddressList {
|
||||
CWHavenSubaddressList(this._wallet);
|
||||
Object _wallet;
|
||||
final Object _wallet;
|
||||
|
||||
@override
|
||||
@computed
|
||||
@@ -71,13 +71,13 @@ class CWHavenSubaddressList extends MoneroSubaddressList {
|
||||
}
|
||||
|
||||
@override
|
||||
void update(Object wallet, {int accountIndex}) {
|
||||
void update(Object wallet, {required int accountIndex}) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.subaddressList.update(accountIndex: accountIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
void refresh(Object wallet, {int accountIndex}) {
|
||||
void refresh(Object wallet, {required int accountIndex}) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.subaddressList.refresh(accountIndex: accountIndex);
|
||||
}
|
||||
@@ -93,7 +93,7 @@ class CWHavenSubaddressList extends MoneroSubaddressList {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> addSubaddress(Object wallet, {int accountIndex, String label}) async {
|
||||
Future<void> addSubaddress(Object wallet, {required int accountIndex, required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.subaddressList
|
||||
.addSubaddress(
|
||||
@@ -103,7 +103,7 @@ class CWHavenSubaddressList extends MoneroSubaddressList {
|
||||
|
||||
@override
|
||||
Future<void> setLabelSubaddress(Object wallet,
|
||||
{int accountIndex, int addressIndex, String label}) async {
|
||||
{required int accountIndex, required int addressIndex, required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.subaddressList
|
||||
.setLabelSubaddress(
|
||||
@@ -115,9 +115,10 @@ class CWHavenSubaddressList extends MoneroSubaddressList {
|
||||
|
||||
class CWHavenWalletDetails extends HavenWalletDetails {
|
||||
CWHavenWalletDetails(this._wallet);
|
||||
Object _wallet;
|
||||
final Object _wallet;
|
||||
|
||||
@computed
|
||||
@override
|
||||
Account get account {
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final acc = havenWallet.walletAddresses.account as monero_account.Account;
|
||||
@@ -125,10 +126,11 @@ class CWHavenWalletDetails extends HavenWalletDetails {
|
||||
}
|
||||
|
||||
@computed
|
||||
@override
|
||||
HavenBalance get balance {
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final balance = havenWallet.balance;
|
||||
return null;
|
||||
throw Exception('Unimplemented');
|
||||
//return HavenBalance(
|
||||
// fullBalance: balance.fullBalance,
|
||||
// unlockedBalance: balance.unlockedBalance);
|
||||
@@ -136,39 +138,48 @@ class CWHavenWalletDetails extends HavenWalletDetails {
|
||||
}
|
||||
|
||||
class CWHaven extends Haven {
|
||||
HavenAccountList getAccountList(Object wallet) {
|
||||
@override
|
||||
HavenAccountList getAccountList(Object wallet) {
|
||||
return CWHavenAccountList(wallet);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
MoneroSubaddressList getSubaddressList(Object wallet) {
|
||||
return CWHavenSubaddressList(wallet);
|
||||
}
|
||||
|
||||
@override
|
||||
TransactionHistoryBase getTransactionHistory(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.transactionHistory;
|
||||
}
|
||||
|
||||
@override
|
||||
HavenWalletDetails getMoneroWalletDetails(Object wallet) {
|
||||
return CWHavenWalletDetails(wallet);
|
||||
}
|
||||
|
||||
int getHeigthByDate({DateTime date}) {
|
||||
@override
|
||||
int getHeigthByDate({required DateTime date}) {
|
||||
return getMoneroHeigthByDate(date: date);
|
||||
}
|
||||
|
||||
@override
|
||||
TransactionPriority getDefaultTransactionPriority() {
|
||||
return MoneroTransactionPriority.slow;
|
||||
return MoneroTransactionPriority.automatic;
|
||||
}
|
||||
|
||||
TransactionPriority deserializeMoneroTransactionPriority({int raw}) {
|
||||
@override
|
||||
TransactionPriority deserializeMoneroTransactionPriority({required int raw}) {
|
||||
return MoneroTransactionPriority.deserialize(raw: raw);
|
||||
}
|
||||
|
||||
@override
|
||||
List<TransactionPriority> getTransactionPriorities() {
|
||||
return MoneroTransactionPriority.all;
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> getMoneroWordList(String language) {
|
||||
switch (language.toLowerCase()) {
|
||||
case 'english':
|
||||
@@ -196,14 +207,15 @@ class CWHaven extends Haven {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
WalletCredentials createHavenRestoreWalletFromKeysCredentials({
|
||||
String name,
|
||||
String spendKey,
|
||||
String viewKey,
|
||||
String address,
|
||||
String password,
|
||||
String language,
|
||||
int height}) {
|
||||
required String name,
|
||||
required String spendKey,
|
||||
required String viewKey,
|
||||
required String address,
|
||||
required String password,
|
||||
required String language,
|
||||
required int height}) {
|
||||
return HavenRestoreWalletFromKeysCredentials(
|
||||
name: name,
|
||||
spendKey: spendKey,
|
||||
@@ -213,8 +225,13 @@ class CWHaven extends Haven {
|
||||
language: language,
|
||||
height: height);
|
||||
}
|
||||
|
||||
WalletCredentials createHavenRestoreWalletFromSeedCredentials({String name, String password, int height, String mnemonic}) {
|
||||
|
||||
@override
|
||||
WalletCredentials createHavenRestoreWalletFromSeedCredentials({
|
||||
required String name,
|
||||
required String password,
|
||||
required int height,
|
||||
required String mnemonic}) {
|
||||
return HavenRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
@@ -222,13 +239,18 @@ class CWHaven extends Haven {
|
||||
mnemonic: mnemonic);
|
||||
}
|
||||
|
||||
WalletCredentials createHavenNewWalletCredentials({String name, String password, String language}) {
|
||||
@override
|
||||
WalletCredentials createHavenNewWalletCredentials({
|
||||
required String name,
|
||||
required String language,
|
||||
String? password}) {
|
||||
return HavenNewWalletCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
language: language);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, String> getKeys(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
final keys = havenWallet.keys;
|
||||
@@ -239,7 +261,11 @@ class CWHaven extends Haven {
|
||||
'publicViewKey': keys.publicViewKey};
|
||||
}
|
||||
|
||||
Object createHavenTransactionCreationCredentials({List<Output> outputs, TransactionPriority priority, String assetType}) {
|
||||
@override
|
||||
Object createHavenTransactionCreationCredentials({
|
||||
required List<Output> outputs,
|
||||
required TransactionPriority priority,
|
||||
required String assetType}) {
|
||||
return HavenTransactionCreationCredentials(
|
||||
outputs: outputs.map((out) => OutputInfo(
|
||||
fiatAmount: out.fiatAmount,
|
||||
@@ -255,53 +281,64 @@ class CWHaven extends Haven {
|
||||
assetType: assetType);
|
||||
}
|
||||
|
||||
String formatterMoneroAmountToString({int amount}) {
|
||||
@override
|
||||
String formatterMoneroAmountToString({required int amount}) {
|
||||
return moneroAmountToString(amount: amount);
|
||||
}
|
||||
|
||||
double formatterMoneroAmountToDouble({int amount}) {
|
||||
|
||||
@override
|
||||
double formatterMoneroAmountToDouble({required int amount}) {
|
||||
return moneroAmountToDouble(amount: amount);
|
||||
}
|
||||
|
||||
int formatterMoneroParseAmount({String amount}) {
|
||||
@override
|
||||
int formatterMoneroParseAmount({required String amount}) {
|
||||
return moneroParseAmount(amount: amount);
|
||||
}
|
||||
|
||||
@override
|
||||
Account getCurrentAccount(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
final acc = havenWallet.walletAddresses.account as monero_account.Account;
|
||||
return Account(id: acc.id, label: acc.label);
|
||||
}
|
||||
|
||||
@override
|
||||
void setCurrentAccount(Object wallet, int id, String label) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.account = monero_account.Account(id: id, label: label);
|
||||
}
|
||||
|
||||
@override
|
||||
void onStartup() {
|
||||
monero_wallet_api.onStartup();
|
||||
}
|
||||
|
||||
@override
|
||||
int getTransactionInfoAccountId(TransactionInfo tx) {
|
||||
final havenTransactionInfo = tx as HavenTransactionInfo;
|
||||
return havenTransactionInfo.accountIndex;
|
||||
}
|
||||
|
||||
@override
|
||||
WalletService createHavenWalletService(Box<WalletInfo> walletInfoSource) {
|
||||
return HavenWalletService(walletInfoSource);
|
||||
}
|
||||
|
||||
@override
|
||||
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.getTransactionAddress(accountIndex, addressIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
CryptoCurrency assetOfTransaction(TransactionInfo tx) {
|
||||
final transaction = tx as HavenTransactionInfo;
|
||||
final asset = CryptoCurrency.fromString(transaction.assetType);
|
||||
return asset;
|
||||
}
|
||||
|
||||
@override
|
||||
List<AssetRate> getAssetRate()
|
||||
=> getRate()
|
||||
.map((rate) => AssetRate(rate.getAssetType(), rate.getRate()))
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cw_core/monero_amount_format.dart';
|
||||
import 'package:cw_core/monero_transaction_priority.dart';
|
||||
import 'package:cw_core/output_info.dart';
|
||||
@@ -14,7 +13,6 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_order.dart';
|
||||
|
||||
class IoniaAnyPay {
|
||||
IoniaAnyPay(this.ioniaService, this.anyPayApi, this.wallet);
|
||||
@@ -24,8 +22,8 @@ class IoniaAnyPay {
|
||||
final WalletBase wallet;
|
||||
|
||||
Future<IoniaAnyPayPaymentInfo> purchase({
|
||||
@required String merchId,
|
||||
@required double amount}) async {
|
||||
required String merchId,
|
||||
required double amount}) async {
|
||||
final invoice = await ioniaService.purchaseGiftCard(
|
||||
merchId: merchId,
|
||||
amount: amount,
|
||||
@@ -40,7 +38,7 @@ class IoniaAnyPay {
|
||||
.map((AnyPayPaymentInstruction instruction) {
|
||||
switch(payment.chain.toUpperCase()) {
|
||||
case AnyPayChain.xmr:
|
||||
return monero.createMoneroTransactionCreationCredentialsRaw(
|
||||
return monero!.createMoneroTransactionCreationCredentialsRaw(
|
||||
outputs: instruction.outputs.map((out) =>
|
||||
OutputInfo(
|
||||
isParsedAddress: false,
|
||||
@@ -50,7 +48,7 @@ class IoniaAnyPay {
|
||||
sendAll: false)).toList(),
|
||||
priority: MoneroTransactionPriority.medium); // FIXME: HARDCODED PRIORITY
|
||||
case AnyPayChain.btc:
|
||||
return bitcoin.createBitcoinTransactionCredentialsRaw(
|
||||
return bitcoin!.createBitcoinTransactionCredentialsRaw(
|
||||
instruction.outputs.map((out) =>
|
||||
OutputInfo(
|
||||
isParsedAddress: false,
|
||||
@@ -59,7 +57,7 @@ class IoniaAnyPay {
|
||||
sendAll: false)).toList(),
|
||||
feeRate: instruction.requiredFeeRate);
|
||||
case AnyPayChain.ltc:
|
||||
return bitcoin.createBitcoinTransactionCredentialsRaw(
|
||||
return bitcoin!.createBitcoinTransactionCredentialsRaw(
|
||||
instruction.outputs.map((out) =>
|
||||
OutputInfo(
|
||||
isParsedAddress: false,
|
||||
@@ -76,8 +74,8 @@ class IoniaAnyPay {
|
||||
.map((PendingTransaction pendingTransaction) {
|
||||
switch (payment.chain.toUpperCase()){
|
||||
case AnyPayChain.xmr:
|
||||
final ptx = monero.pendingTransactionInfo(pendingTransaction);
|
||||
return AnyPayTransaction(ptx['hex'], id: ptx['id'], key: ptx['key']);
|
||||
final ptx = monero!.pendingTransactionInfo(pendingTransaction);
|
||||
return AnyPayTransaction(ptx['hex'] ?? '', id: ptx['id'] ?? '', key: ptx['key']);
|
||||
default:
|
||||
return AnyPayTransaction(pendingTransaction.hex, id: pendingTransaction.id, key: null);
|
||||
}
|
||||
|
||||
+101
-105
@@ -1,7 +1,6 @@
|
||||
import 'dart:convert';
|
||||
import 'package:cake_wallet/ionia/ionia_merchant.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_order.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_user_credentials.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_virtual_card.dart';
|
||||
@@ -11,6 +10,7 @@ import 'package:cake_wallet/ionia/ionia_gift_card.dart';
|
||||
class IoniaApi {
|
||||
static const baseUri = 'api.ionia.io';
|
||||
static const pathPrefix = 'cake';
|
||||
static const requestedUUIDHeader = 'requestedUUID';
|
||||
static final createUserUri = Uri.https(baseUri, '/$pathPrefix/CreateUser');
|
||||
static final verifyEmailUri = Uri.https(baseUri, '/$pathPrefix/VerifyEmail');
|
||||
static final signInUri = Uri.https(baseUri, '/$pathPrefix/SignIn');
|
||||
@@ -26,19 +26,18 @@ class IoniaApi {
|
||||
|
||||
// Create user
|
||||
|
||||
Future<String> createUser(String email, {@required String clientId}) async {
|
||||
Future<String> createUser(String email, {required String clientId}) async {
|
||||
final headers = <String, String>{'clientId': clientId};
|
||||
final query = <String, String>{'emailAddress': email};
|
||||
final uri = createUserUri.replace(queryParameters: query);
|
||||
final response = await put(uri, headers: headers);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
// throw exception
|
||||
return null;
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final bodyJson = json.decode(response.body) as Map<String, Object>;
|
||||
final data = bodyJson['Data'] as Map<String, Object>;
|
||||
final bodyJson = json.decode(response.body) as Map<String, dynamic>;
|
||||
final data = bodyJson['Data'] as Map<String, dynamic>;
|
||||
final isSuccessful = bodyJson['Successful'] as bool;
|
||||
|
||||
if (!isSuccessful) {
|
||||
@@ -51,25 +50,22 @@ class IoniaApi {
|
||||
// Verify email
|
||||
|
||||
Future<IoniaUserCredentials> verifyEmail({
|
||||
@required String username,
|
||||
@required String email,
|
||||
@required String code,
|
||||
@required String clientId}) async {
|
||||
required String email,
|
||||
required String code,
|
||||
required String clientId}) async {
|
||||
final headers = <String, String>{
|
||||
'clientId': clientId,
|
||||
'username': username,
|
||||
'EmailAddress': email};
|
||||
final query = <String, String>{'verificationCode': code};
|
||||
final uri = verifyEmailUri.replace(queryParameters: query);
|
||||
final response = await put(uri, headers: headers);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
// throw exception
|
||||
return null;
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final bodyJson = json.decode(response.body) as Map<String, Object>;
|
||||
final data = bodyJson['Data'] as Map<String, Object>;
|
||||
final bodyJson = json.decode(response.body) as Map<String, dynamic>;
|
||||
final data = bodyJson['Data'] as Map<String, dynamic>;
|
||||
final isSuccessful = bodyJson['Successful'] as bool;
|
||||
|
||||
if (!isSuccessful) {
|
||||
@@ -77,40 +73,37 @@ class IoniaApi {
|
||||
}
|
||||
|
||||
final password = data['password'] as String;
|
||||
username = data['username'] as String;
|
||||
final username = data['username'] as String;
|
||||
return IoniaUserCredentials(username, password);
|
||||
}
|
||||
|
||||
// Sign In
|
||||
|
||||
Future<String> signIn(String email, {@required String clientId}) async {
|
||||
Future<void> signIn(String email, {required String clientId}) async {
|
||||
final headers = <String, String>{'clientId': clientId};
|
||||
final query = <String, String>{'emailAddress': email};
|
||||
final uri = signInUri.replace(queryParameters: query);
|
||||
final response = await put(uri, headers: headers);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
// throw exception
|
||||
return null;
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final bodyJson = json.decode(response.body) as Map<String, Object>;
|
||||
final data = bodyJson['Data'] as Map<String, Object>;
|
||||
final bodyJson = json.decode(response.body) as Map<String, dynamic>;
|
||||
final data = bodyJson['Data'] as Map<String, dynamic>;
|
||||
final isSuccessful = bodyJson['Successful'] as bool;
|
||||
|
||||
if (!isSuccessful) {
|
||||
throw Exception(data['ErrorMessage'] as String);
|
||||
}
|
||||
|
||||
return data['username'] as String;
|
||||
}
|
||||
|
||||
// Get virtual card
|
||||
|
||||
Future<IoniaVirtualCard> getCards({
|
||||
@required String username,
|
||||
@required String password,
|
||||
@required String clientId}) async {
|
||||
required String username,
|
||||
required String password,
|
||||
required String clientId}) async {
|
||||
final headers = <String, String>{
|
||||
'clientId': clientId,
|
||||
'username': username,
|
||||
@@ -118,28 +111,27 @@ class IoniaApi {
|
||||
final response = await post(getCardsUri, headers: headers);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
// throw exception
|
||||
return null;
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final bodyJson = json.decode(response.body) as Map<String, Object>;
|
||||
final data = bodyJson['Data'] as Map<String, Object>;
|
||||
final bodyJson = json.decode(response.body) as Map<String, dynamic>;
|
||||
final data = bodyJson['Data'] as Map<String, dynamic>;
|
||||
final isSuccessful = bodyJson['Successful'] as bool;
|
||||
|
||||
if (!isSuccessful) {
|
||||
throw Exception(data['message'] as String);
|
||||
}
|
||||
|
||||
final virtualCard = data['VirtualCard'] as Map<String, Object>;
|
||||
final virtualCard = data['VirtualCard'] as Map<String, dynamic>;
|
||||
return IoniaVirtualCard.fromMap(virtualCard);
|
||||
}
|
||||
|
||||
// Create virtual card
|
||||
|
||||
Future<IoniaVirtualCard> createCard({
|
||||
@required String username,
|
||||
@required String password,
|
||||
@required String clientId}) async {
|
||||
required String username,
|
||||
required String password,
|
||||
required String clientId}) async {
|
||||
final headers = <String, String>{
|
||||
'clientId': clientId,
|
||||
'username': username,
|
||||
@@ -147,13 +139,12 @@ class IoniaApi {
|
||||
final response = await post(createCardUri, headers: headers);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
// throw exception
|
||||
return null;
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final bodyJson = json.decode(response.body) as Map<String, Object>;
|
||||
final data = bodyJson['Data'] as Map<String, Object>;
|
||||
final isSuccessful = bodyJson['Successful'] as bool;
|
||||
final bodyJson = json.decode(response.body) as Map<String, dynamic>;
|
||||
final data = bodyJson['Data'] as Map<String, dynamic>;
|
||||
final isSuccessful = bodyJson['Successful'] as bool? ?? false;
|
||||
|
||||
if (!isSuccessful) {
|
||||
throw Exception(data['message'] as String);
|
||||
@@ -165,9 +156,9 @@ class IoniaApi {
|
||||
// Get Merchants
|
||||
|
||||
Future<List<IoniaMerchant>> getMerchants({
|
||||
@required String username,
|
||||
@required String password,
|
||||
@required String clientId}) async {
|
||||
required String username,
|
||||
required String password,
|
||||
required String clientId}) async {
|
||||
final headers = <String, String>{
|
||||
'clientId': clientId,
|
||||
'username': username,
|
||||
@@ -179,32 +170,33 @@ class IoniaApi {
|
||||
}
|
||||
|
||||
final decodedBody = json.decode(response.body) as Map<String, dynamic>;
|
||||
final isSuccessful = decodedBody['Successful'] as bool ?? false;
|
||||
final isSuccessful = decodedBody['Successful'] as bool? ?? false;
|
||||
|
||||
if (!isSuccessful) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final data = decodedBody['Data'] as List<dynamic>;
|
||||
return data.map((dynamic e) {
|
||||
try {
|
||||
final element = e as Map<String, dynamic>;
|
||||
return IoniaMerchant.fromJsonMap(element);
|
||||
} catch(_) {
|
||||
return null;
|
||||
}
|
||||
}).where((e) => e != null)
|
||||
.toList();
|
||||
final merch = <IoniaMerchant>[];
|
||||
|
||||
for (final item in data) {
|
||||
try {
|
||||
final element = item as Map<String, dynamic>;
|
||||
merch.add(IoniaMerchant.fromJsonMap(element));
|
||||
} catch(_) {}
|
||||
}
|
||||
|
||||
return merch;
|
||||
}
|
||||
|
||||
// Get Merchants By Filter
|
||||
|
||||
Future<List<IoniaMerchant>> getMerchantsByFilter({
|
||||
@required String username,
|
||||
@required String password,
|
||||
@required String clientId,
|
||||
String search,
|
||||
List<IoniaCategory> categories,
|
||||
required String username,
|
||||
required String password,
|
||||
required String clientId,
|
||||
String? search,
|
||||
List<IoniaCategory>? categories,
|
||||
int merchantFilterType = 0}) async {
|
||||
// MerchantFilterType: {All = 0, Nearby = 1, Popular = 2, Online = 3, MyFaves = 4, Search = 5}
|
||||
|
||||
@@ -233,37 +225,40 @@ class IoniaApi {
|
||||
}
|
||||
|
||||
final decodedBody = json.decode(response.body) as Map<String, dynamic>;
|
||||
final isSuccessful = decodedBody['Successful'] as bool ?? false;
|
||||
final isSuccessful = decodedBody['Successful'] as bool? ?? false;
|
||||
|
||||
if (!isSuccessful) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final data = decodedBody['Data'] as List<dynamic>;
|
||||
return data.map((dynamic e) {
|
||||
try {
|
||||
final element = e['Merchant'] as Map<String, dynamic>;
|
||||
return IoniaMerchant.fromJsonMap(element);
|
||||
} catch(_) {
|
||||
return null;
|
||||
}
|
||||
}).where((e) => e != null)
|
||||
.toList();
|
||||
final merch = <IoniaMerchant>[];
|
||||
|
||||
for (final item in data) {
|
||||
try {
|
||||
final element = item['Merchant'] as Map<String, dynamic>;
|
||||
merch.add(IoniaMerchant.fromJsonMap(element));
|
||||
} catch(_) {}
|
||||
}
|
||||
|
||||
return merch;
|
||||
}
|
||||
|
||||
// Purchase Gift Card
|
||||
|
||||
Future<IoniaOrder> purchaseGiftCard({
|
||||
@required String merchId,
|
||||
@required double amount,
|
||||
@required String currency,
|
||||
@required String username,
|
||||
@required String password,
|
||||
@required String clientId}) async {
|
||||
required String requestedUUID,
|
||||
required String merchId,
|
||||
required double amount,
|
||||
required String currency,
|
||||
required String username,
|
||||
required String password,
|
||||
required String clientId}) async {
|
||||
final headers = <String, String>{
|
||||
'clientId': clientId,
|
||||
'username': username,
|
||||
'password': password,
|
||||
requestedUUIDHeader: requestedUUID,
|
||||
'Content-Type': 'application/json'};
|
||||
final body = <String, dynamic>{
|
||||
'Amount': amount,
|
||||
@@ -276,7 +271,7 @@ class IoniaApi {
|
||||
}
|
||||
|
||||
final decodedBody = json.decode(response.body) as Map<String, dynamic>;
|
||||
final isSuccessful = decodedBody['Successful'] as bool ?? false;
|
||||
final isSuccessful = decodedBody['Successful'] as bool? ?? false;
|
||||
|
||||
if (!isSuccessful) {
|
||||
throw Exception(decodedBody['ErrorMessage'] as String);
|
||||
@@ -289,9 +284,9 @@ class IoniaApi {
|
||||
// Get Current User Gift Card Summaries
|
||||
|
||||
Future<List<IoniaGiftCard>> getCurrentUserGiftCardSummaries({
|
||||
@required String username,
|
||||
@required String password,
|
||||
@required String clientId}) async {
|
||||
required String username,
|
||||
required String password,
|
||||
required String clientId}) async {
|
||||
final headers = <String, String>{
|
||||
'clientId': clientId,
|
||||
'username': username,
|
||||
@@ -303,32 +298,33 @@ class IoniaApi {
|
||||
}
|
||||
|
||||
final decodedBody = json.decode(response.body) as Map<String, dynamic>;
|
||||
final isSuccessful = decodedBody['Successful'] as bool ?? false;
|
||||
final isSuccessful = decodedBody['Successful'] as bool? ?? false;
|
||||
|
||||
if (!isSuccessful) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final data = decodedBody['Data'] as List<dynamic>;
|
||||
return data.map((dynamic e) {
|
||||
try {
|
||||
final element = e as Map<String, dynamic>;
|
||||
return IoniaGiftCard.fromJsonMap(element);
|
||||
} catch(e) {
|
||||
return null;
|
||||
}
|
||||
}).where((e) => e != null)
|
||||
.toList();
|
||||
final cards = <IoniaGiftCard>[];
|
||||
|
||||
for (final item in data) {
|
||||
try {
|
||||
final element = item as Map<String, dynamic>;
|
||||
cards.add(IoniaGiftCard.fromJsonMap(element));
|
||||
} catch(_) {}
|
||||
}
|
||||
|
||||
return cards;
|
||||
}
|
||||
|
||||
// Charge Gift Card
|
||||
|
||||
Future<void> chargeGiftCard({
|
||||
@required String username,
|
||||
@required String password,
|
||||
@required String clientId,
|
||||
@required int giftCardId,
|
||||
@required double amount}) async {
|
||||
required String username,
|
||||
required String password,
|
||||
required String clientId,
|
||||
required int giftCardId,
|
||||
required double amount}) async {
|
||||
final headers = <String, String>{
|
||||
'clientId': clientId,
|
||||
'username': username,
|
||||
@@ -347,11 +343,11 @@ class IoniaApi {
|
||||
}
|
||||
|
||||
final decodedBody = json.decode(response.body) as Map<String, dynamic>;
|
||||
final isSuccessful = decodedBody['Successful'] as bool ?? false;
|
||||
final isSuccessful = decodedBody['Successful'] as bool? ?? false;
|
||||
|
||||
if (!isSuccessful) {
|
||||
final data = decodedBody['Data'] as Map<String, dynamic>;
|
||||
final msg = data['Message'] as String ?? '';
|
||||
final msg = data['Message'] as String? ?? '';
|
||||
|
||||
if (msg.isNotEmpty) {
|
||||
throw Exception(msg);
|
||||
@@ -364,10 +360,10 @@ class IoniaApi {
|
||||
// Get Gift Card
|
||||
|
||||
Future<IoniaGiftCard> getGiftCard({
|
||||
@required String username,
|
||||
@required String password,
|
||||
@required String clientId,
|
||||
@required int id}) async {
|
||||
required String username,
|
||||
required String password,
|
||||
required String clientId,
|
||||
required int id}) async {
|
||||
final headers = <String, String>{
|
||||
'clientId': clientId,
|
||||
'username': username,
|
||||
@@ -384,7 +380,7 @@ class IoniaApi {
|
||||
}
|
||||
|
||||
final decodedBody = json.decode(response.body) as Map<String, dynamic>;
|
||||
final isSuccessful = decodedBody['Successful'] as bool ?? false;
|
||||
final isSuccessful = decodedBody['Successful'] as bool? ?? false;
|
||||
|
||||
if (!isSuccessful) {
|
||||
final msg = decodedBody['ErrorMessage'] as String ?? '';
|
||||
@@ -403,11 +399,11 @@ class IoniaApi {
|
||||
// Payment Status
|
||||
|
||||
Future<int> getPaymentStatus({
|
||||
@required String username,
|
||||
@required String password,
|
||||
@required String clientId,
|
||||
@required String orderId,
|
||||
@required String paymentId}) async {
|
||||
required String username,
|
||||
required String password,
|
||||
required String clientId,
|
||||
required String orderId,
|
||||
required String paymentId}) async {
|
||||
final headers = <String, String>{
|
||||
'clientId': clientId,
|
||||
'username': username,
|
||||
@@ -426,7 +422,7 @@ class IoniaApi {
|
||||
}
|
||||
|
||||
final decodedBody = json.decode(response.body) as Map<String, dynamic>;
|
||||
final isSuccessful = decodedBody['Successful'] as bool ?? false;
|
||||
final isSuccessful = decodedBody['Successful'] as bool? ?? false;
|
||||
|
||||
if (!isSuccessful) {
|
||||
final msg = decodedBody['ErrorMessage'] as String ?? '';
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
class IoniaCategory {
|
||||
const IoniaCategory({this.index, this.title, this.ids, this.iconPath});
|
||||
const IoniaCategory({
|
||||
required this.index,
|
||||
required this.title,
|
||||
required this.ids,
|
||||
required this.iconPath});
|
||||
|
||||
static const allCategories = <IoniaCategory>[all, apparel, onlineOnly, food, entertainment, delivery, travel];
|
||||
static const all = IoniaCategory(index: 0, title: 'All', ids: [], iconPath: 'assets/images/category.png');
|
||||
|
||||
@@ -10,7 +10,7 @@ class IoniaCreateStateSuccess extends IoniaCreateAccountState {}
|
||||
class IoniaCreateStateLoading extends IoniaCreateAccountState {}
|
||||
|
||||
class IoniaCreateStateFailure extends IoniaCreateAccountState {
|
||||
IoniaCreateStateFailure({@required this.error});
|
||||
IoniaCreateStateFailure({required this.error});
|
||||
|
||||
final String error;
|
||||
}
|
||||
@@ -26,7 +26,7 @@ class IoniaOtpSendDisabled extends IoniaOtpState {}
|
||||
class IoniaOtpSendEnabled extends IoniaOtpState {}
|
||||
|
||||
class IoniaOtpFailure extends IoniaOtpState {
|
||||
IoniaOtpFailure({@required this.error});
|
||||
IoniaOtpFailure({required this.error});
|
||||
|
||||
final String error;
|
||||
}
|
||||
@@ -38,7 +38,7 @@ class IoniaCreateCardSuccess extends IoniaCreateCardState {}
|
||||
class IoniaCreateCardLoading extends IoniaCreateCardState {}
|
||||
|
||||
class IoniaCreateCardFailure extends IoniaCreateCardState {
|
||||
IoniaCreateCardFailure({@required this.error});
|
||||
IoniaCreateCardFailure({required this.error});
|
||||
|
||||
final String error;
|
||||
}
|
||||
@@ -52,7 +52,17 @@ class IoniaFetchingCard extends IoniaFetchCardState {}
|
||||
class IoniaFetchCardFailure extends IoniaFetchCardState {}
|
||||
|
||||
class IoniaCardSuccess extends IoniaFetchCardState {
|
||||
IoniaCardSuccess({@required this.card});
|
||||
IoniaCardSuccess({required this.card});
|
||||
|
||||
final IoniaVirtualCard card;
|
||||
}
|
||||
|
||||
abstract class IoniaMerchantState {}
|
||||
|
||||
class InitialIoniaMerchantLoadingState extends IoniaMerchantState {}
|
||||
|
||||
class IoniaLoadingMerchantState extends IoniaMerchantState {}
|
||||
|
||||
class IoniaLoadedMerchantState extends IoniaMerchantState {}
|
||||
|
||||
|
||||
|
||||
@@ -4,25 +4,25 @@ import 'package:flutter/foundation.dart';
|
||||
|
||||
class IoniaGiftCard {
|
||||
IoniaGiftCard({
|
||||
@required this.id,
|
||||
@required this.merchantId,
|
||||
@required this.legalName,
|
||||
@required this.systemName,
|
||||
@required this.barcodeUrl,
|
||||
@required this.cardNumber,
|
||||
@required this.cardPin,
|
||||
@required this.instructions,
|
||||
@required this.tip,
|
||||
@required this.purchaseAmount,
|
||||
@required this.actualAmount,
|
||||
@required this.totalTransactionAmount,
|
||||
@required this.totalDashTransactionAmount,
|
||||
@required this.remainingAmount,
|
||||
@required this.createdDateFormatted,
|
||||
@required this.lastTransactionDateFormatted,
|
||||
@required this.isActive,
|
||||
@required this.isEmpty,
|
||||
@required this.logoUrl});
|
||||
required this.id,
|
||||
required this.merchantId,
|
||||
required this.legalName,
|
||||
required this.systemName,
|
||||
required this.barcodeUrl,
|
||||
required this.cardNumber,
|
||||
required this.cardPin,
|
||||
required this.instructions,
|
||||
required this.tip,
|
||||
required this.purchaseAmount,
|
||||
required this.actualAmount,
|
||||
required this.totalTransactionAmount,
|
||||
required this.totalDashTransactionAmount,
|
||||
required this.remainingAmount,
|
||||
required this.createdDateFormatted,
|
||||
required this.lastTransactionDateFormatted,
|
||||
required this.isActive,
|
||||
required this.isEmpty,
|
||||
required this.logoUrl});
|
||||
|
||||
factory IoniaGiftCard.fromJsonMap(Map<String, dynamic> element) {
|
||||
return IoniaGiftCard(
|
||||
@@ -60,10 +60,11 @@ class IoniaGiftCard {
|
||||
final double actualAmount;
|
||||
final double totalTransactionAmount;
|
||||
final double totalDashTransactionAmount;
|
||||
final double remainingAmount;
|
||||
double remainingAmount;
|
||||
final String createdDateFormatted;
|
||||
final String lastTransactionDateFormatted;
|
||||
final bool isActive;
|
||||
final bool isEmpty;
|
||||
final String logoUrl;
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@ class IoniaGiftCardInstruction {
|
||||
|
||||
factory IoniaGiftCardInstruction.fromJsonMap(Map<String, dynamic> element) {
|
||||
return IoniaGiftCardInstruction(
|
||||
toBeginningOfSentenceCase(element['title'] as String ?? ''),
|
||||
toBeginningOfSentenceCase(element['title'] as String? ?? '') ?? '',
|
||||
element['description'] as String);
|
||||
}
|
||||
|
||||
|
||||
+35
-129
@@ -1,63 +1,31 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_gift_card_instruction.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class IoniaMerchant {
|
||||
IoniaMerchant({
|
||||
@required this.id,
|
||||
@required this.legalName,
|
||||
@required this.systemName,
|
||||
@required this.description,
|
||||
@required this.website,
|
||||
@required this.termsAndConditions,
|
||||
@required this.logoUrl,
|
||||
@required this.cardImageUrl,
|
||||
@required this.cardholderAgreement,
|
||||
@required this.purchaseFee,
|
||||
@required this.revenueShare,
|
||||
@required this.marketingFee,
|
||||
@required this.minimumDiscount,
|
||||
@required this.level1,
|
||||
@required this.level2,
|
||||
@required this.level3,
|
||||
@required this.level4,
|
||||
@required this.level5,
|
||||
@required this.level6,
|
||||
@required this.level7,
|
||||
@required this.isActive,
|
||||
@required this.isDeleted,
|
||||
@required this.isOnline,
|
||||
@required this.isPhysical,
|
||||
@required this.isVariablePurchase,
|
||||
@required this.minimumCardPurchase,
|
||||
@required this.maximumCardPurchase,
|
||||
@required this.acceptsTips,
|
||||
@required this.createdDateFormatted,
|
||||
@required this.createdBy,
|
||||
@required this.isRegional,
|
||||
@required this.modifiedDateFormatted,
|
||||
@required this.modifiedBy,
|
||||
@required this.usageInstructions,
|
||||
@required this.usageInstructionsBak,
|
||||
@required this.paymentGatewayId,
|
||||
@required this.giftCardGatewayId,
|
||||
@required this.isHtmlDescription,
|
||||
@required this.purchaseInstructions,
|
||||
@required this.balanceInstructions,
|
||||
@required this.amountPerCard,
|
||||
@required this.processingMessage,
|
||||
@required this.hasBarcode,
|
||||
@required this.hasInventory,
|
||||
@required this.isVoidable,
|
||||
@required this.receiptMessage,
|
||||
@required this.cssBorderCode,
|
||||
@required this.instructions,
|
||||
@required this.alderSku,
|
||||
@required this.ngcSku,
|
||||
@required this.acceptedCurrency,
|
||||
@required this.deepLink,
|
||||
@required this.isPayLater,
|
||||
@required this.savingsPercentage});
|
||||
required this.id,
|
||||
required this.legalName,
|
||||
required this.systemName,
|
||||
required this.description,
|
||||
required this.website,
|
||||
required this.termsAndConditions,
|
||||
required this.logoUrl,
|
||||
required this.cardImageUrl,
|
||||
required this.cardholderAgreement,
|
||||
required this.isActive,
|
||||
required this.isOnline,
|
||||
required this.isPhysical,
|
||||
required this.isVariablePurchase,
|
||||
required this.minimumCardPurchase,
|
||||
required this.maximumCardPurchase,
|
||||
required this.acceptsTips,
|
||||
required this.createdDateFormatted,
|
||||
required this.modifiedDateFormatted,
|
||||
required this.usageInstructions,
|
||||
required this.usageInstructionsBak,
|
||||
required this.hasBarcode,
|
||||
required this.instructions,
|
||||
required this.savingsPercentage});
|
||||
|
||||
factory IoniaMerchant.fromJsonMap(Map<String, dynamic> element) {
|
||||
return IoniaMerchant(
|
||||
@@ -70,50 +38,19 @@ class IoniaMerchant {
|
||||
logoUrl: element["LogoUrl"] as String,
|
||||
cardImageUrl: element["CardImageUrl"] as String,
|
||||
cardholderAgreement: element["CardholderAgreement"] as String,
|
||||
purchaseFee: element["PurchaseFee"] as double,
|
||||
revenueShare: element["RevenueShare"] as double,
|
||||
marketingFee: element["MarketingFee"] as double,
|
||||
minimumDiscount: element["MinimumDiscount"] as double,
|
||||
level1: element["Level1"] as double,
|
||||
level2: element["Level2"] as double,
|
||||
level3: element["Level3"] as double,
|
||||
level4: element["Level4"] as double,
|
||||
level5: element["Level5"] as double,
|
||||
level6: element["Level6"] as double,
|
||||
level7: element["Level7"] as double,
|
||||
isActive: element["IsActive"] as bool,
|
||||
isDeleted: element["IsDeleted"] as bool,
|
||||
isActive: element["IsActive"] as bool?,
|
||||
isOnline: element["IsOnline"] as bool,
|
||||
isPhysical: element["IsPhysical"] as bool,
|
||||
isVariablePurchase: element["IsVariablePurchase"] as bool,
|
||||
minimumCardPurchase: element["MinimumCardPurchase"] as double,
|
||||
maximumCardPurchase: element["MaximumCardPurchase"] as double,
|
||||
acceptsTips: element["AcceptsTips"] as bool,
|
||||
createdDateFormatted: element["CreatedDate"] as String,
|
||||
createdBy: element["CreatedBy"] as int,
|
||||
isRegional: element["IsRegional"] as bool,
|
||||
modifiedDateFormatted: element["ModifiedDate"] as String,
|
||||
modifiedBy: element["ModifiedBy"] as int,
|
||||
usageInstructions: element["UsageInstructions"] as String,
|
||||
usageInstructionsBak: element["UsageInstructionsBak"] as String,
|
||||
paymentGatewayId: element["PaymentGatewayId"] as int,
|
||||
giftCardGatewayId: element["GiftCardGatewayId"] as int ,
|
||||
isHtmlDescription: element["IsHtmlDescription"] as bool,
|
||||
purchaseInstructions: element["PurchaseInstructions"] as String,
|
||||
balanceInstructions: element["BalanceInstructions"] as String,
|
||||
amountPerCard: element["AmountPerCard"] as double,
|
||||
processingMessage: element["ProcessingMessage"] as String,
|
||||
createdDateFormatted: element["CreatedDate"] as String?,
|
||||
modifiedDateFormatted: element["ModifiedDate"] as String?,
|
||||
usageInstructions: element["UsageInstructions"] as String?,
|
||||
usageInstructionsBak: element["UsageInstructionsBak"] as String?,
|
||||
hasBarcode: element["HasBarcode"] as bool,
|
||||
hasInventory: element["HasInventory"] as bool,
|
||||
isVoidable: element["IsVoidable"] as bool,
|
||||
receiptMessage: element["ReceiptMessage"] as String,
|
||||
cssBorderCode: element["CssBorderCode"] as String,
|
||||
instructions: IoniaGiftCardInstruction.parseListOfInstructions(element['PaymentInstructions'] as String),
|
||||
alderSku: element["AlderSku"] as String,
|
||||
ngcSku: element["NgcSku"] as String,
|
||||
acceptedCurrency: element["AcceptedCurrency"] as String,
|
||||
deepLink: element["DeepLink"] as String,
|
||||
isPayLater: element["IsPayLater"] as bool,
|
||||
savingsPercentage: element["SavingsPercentage"] as double);
|
||||
}
|
||||
|
||||
@@ -126,50 +63,19 @@ class IoniaMerchant {
|
||||
final String logoUrl;
|
||||
final String cardImageUrl;
|
||||
final String cardholderAgreement;
|
||||
final double purchaseFee;
|
||||
final double revenueShare;
|
||||
final double marketingFee;
|
||||
final double minimumDiscount;
|
||||
final double level1;
|
||||
final double level2;
|
||||
final double level3;
|
||||
final double level4;
|
||||
final double level5;
|
||||
final double level6;
|
||||
final double level7;
|
||||
final bool isActive;
|
||||
final bool isDeleted;
|
||||
final bool? isActive;
|
||||
final bool isOnline;
|
||||
final bool isPhysical;
|
||||
final bool? isPhysical;
|
||||
final bool isVariablePurchase;
|
||||
final double minimumCardPurchase;
|
||||
final double maximumCardPurchase;
|
||||
final bool acceptsTips;
|
||||
final String createdDateFormatted;
|
||||
final int createdBy;
|
||||
final bool isRegional;
|
||||
final String modifiedDateFormatted;
|
||||
final int modifiedBy;
|
||||
final String usageInstructions;
|
||||
final String usageInstructionsBak;
|
||||
final int paymentGatewayId;
|
||||
final int giftCardGatewayId;
|
||||
final bool isHtmlDescription;
|
||||
final String purchaseInstructions;
|
||||
final String balanceInstructions;
|
||||
final double amountPerCard;
|
||||
final String processingMessage;
|
||||
final String? createdDateFormatted;
|
||||
final String? modifiedDateFormatted;
|
||||
final String? usageInstructions;
|
||||
final String? usageInstructionsBak;
|
||||
final bool hasBarcode;
|
||||
final bool hasInventory;
|
||||
final bool isVoidable;
|
||||
final String receiptMessage;
|
||||
final String cssBorderCode;
|
||||
final List<IoniaGiftCardInstruction> instructions;
|
||||
final String alderSku;
|
||||
final String ngcSku;
|
||||
final String acceptedCurrency;
|
||||
final String deepLink;
|
||||
final bool isPayLater;
|
||||
final double savingsPercentage;
|
||||
|
||||
double get discount => savingsPercentage;
|
||||
@@ -181,7 +87,7 @@ class IoniaMerchant {
|
||||
status += S.current.online;
|
||||
}
|
||||
|
||||
if (isPhysical) {
|
||||
if (isPhysical ?? false) {
|
||||
if (status.isNotEmpty) {
|
||||
status = '$status & ';
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class IoniaOrder {
|
||||
IoniaOrder({@required this.id,
|
||||
@required this.uri,
|
||||
@required this.currency,
|
||||
@required this.amount,
|
||||
@required this.paymentId});
|
||||
IoniaOrder({required this.id,
|
||||
required this.uri,
|
||||
required this.currency,
|
||||
required this.amount,
|
||||
required this.paymentId});
|
||||
factory IoniaOrder.fromMap(Map<String, dynamic> obj) {
|
||||
return IoniaOrder(
|
||||
id: obj['order_id'] as String,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import 'package:cake_wallet/ionia/ionia_merchant.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_order.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_virtual_card.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/ionia/ionia_api.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_category.dart';
|
||||
import 'package:platform_device_id/platform_device_id.dart';
|
||||
|
||||
class IoniaService {
|
||||
IoniaService(this.secureStorage, this.ioniaApi);
|
||||
@@ -31,9 +31,8 @@ class IoniaService {
|
||||
// Verify email
|
||||
|
||||
Future<void> verifyEmail(String code) async {
|
||||
final username = await secureStorage.read(key: ioniaUsernameStorageKey);
|
||||
final email = await secureStorage.read(key: ioniaEmailStorageKey);
|
||||
final credentials = await ioniaApi.verifyEmail(email: email, username: username, code: code, clientId: clientId);
|
||||
final email = (await secureStorage.read(key: ioniaEmailStorageKey))!;
|
||||
final credentials = await ioniaApi.verifyEmail(email: email, code: code, clientId: clientId);
|
||||
await secureStorage.write(key: ioniaPasswordStorageKey, value: credentials.password);
|
||||
await secureStorage.write(key: ioniaUsernameStorageKey, value: credentials.username);
|
||||
}
|
||||
@@ -41,13 +40,12 @@ class IoniaService {
|
||||
// Sign In
|
||||
|
||||
Future<void> signIn(String email) async {
|
||||
final username = await ioniaApi.signIn(email, clientId: clientId);
|
||||
await ioniaApi.signIn(email, clientId: clientId);
|
||||
await secureStorage.write(key: ioniaEmailStorageKey, value: email);
|
||||
await secureStorage.write(key: ioniaUsernameStorageKey, value: username);
|
||||
}
|
||||
|
||||
Future<String> getUserEmail() async {
|
||||
return secureStorage.read(key: ioniaEmailStorageKey);
|
||||
return (await secureStorage.read(key: ioniaEmailStorageKey))!;
|
||||
}
|
||||
|
||||
// Check is user logined
|
||||
@@ -68,35 +66,35 @@ class IoniaService {
|
||||
// Create virtual card
|
||||
|
||||
Future<IoniaVirtualCard> createCard() async {
|
||||
final username = await secureStorage.read(key: ioniaUsernameStorageKey);
|
||||
final password = await secureStorage.read(key: ioniaPasswordStorageKey);
|
||||
final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
|
||||
final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
|
||||
return ioniaApi.createCard(username: username, password: password, clientId: clientId);
|
||||
}
|
||||
|
||||
// Get virtual card
|
||||
|
||||
Future<IoniaVirtualCard> getCard() async {
|
||||
final username = await secureStorage.read(key: ioniaUsernameStorageKey);
|
||||
final password = await secureStorage.read(key: ioniaPasswordStorageKey);
|
||||
final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
|
||||
final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
|
||||
return ioniaApi.getCards(username: username, password: password, clientId: clientId);
|
||||
}
|
||||
|
||||
// Get Merchants
|
||||
|
||||
Future<List<IoniaMerchant>> getMerchants() async {
|
||||
final username = await secureStorage.read(key: ioniaUsernameStorageKey);
|
||||
final password = await secureStorage.read(key: ioniaPasswordStorageKey);
|
||||
final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
|
||||
final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
|
||||
return ioniaApi.getMerchants(username: username, password: password, clientId: clientId);
|
||||
}
|
||||
|
||||
// Get Merchants By Filter
|
||||
|
||||
Future<List<IoniaMerchant>> getMerchantsByFilter({
|
||||
String search,
|
||||
List<IoniaCategory> categories,
|
||||
String? search,
|
||||
List<IoniaCategory>? categories,
|
||||
int merchantFilterType = 0}) async {
|
||||
final username = await secureStorage.read(key: ioniaUsernameStorageKey);
|
||||
final password = await secureStorage.read(key: ioniaPasswordStorageKey);
|
||||
final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
|
||||
final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
|
||||
return ioniaApi.getMerchantsByFilter(
|
||||
username: username,
|
||||
password: password,
|
||||
@@ -109,12 +107,14 @@ class IoniaService {
|
||||
// Purchase Gift Card
|
||||
|
||||
Future<IoniaOrder> purchaseGiftCard({
|
||||
@required String merchId,
|
||||
@required double amount,
|
||||
@required String currency}) async {
|
||||
final username = await secureStorage.read(key: ioniaUsernameStorageKey);
|
||||
final password = await secureStorage.read(key: ioniaPasswordStorageKey);
|
||||
required String merchId,
|
||||
required double amount,
|
||||
required String currency}) async {
|
||||
final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
|
||||
final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
|
||||
final deviceId = await PlatformDeviceId.getDeviceId;
|
||||
return ioniaApi.purchaseGiftCard(
|
||||
requestedUUID: deviceId!,
|
||||
merchId: merchId,
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
@@ -126,18 +126,18 @@ class IoniaService {
|
||||
// Get Current User Gift Card Summaries
|
||||
|
||||
Future<List<IoniaGiftCard>> getCurrentUserGiftCardSummaries() async {
|
||||
final username = await secureStorage.read(key: ioniaUsernameStorageKey);
|
||||
final password = await secureStorage.read(key: ioniaPasswordStorageKey);
|
||||
final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
|
||||
final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
|
||||
return ioniaApi.getCurrentUserGiftCardSummaries(username: username, password: password, clientId: clientId);
|
||||
}
|
||||
|
||||
// Charge Gift Card
|
||||
|
||||
Future<void> chargeGiftCard({
|
||||
@required int giftCardId,
|
||||
@required double amount}) async {
|
||||
final username = await secureStorage.read(key: ioniaUsernameStorageKey);
|
||||
final password = await secureStorage.read(key: ioniaPasswordStorageKey);
|
||||
required int giftCardId,
|
||||
required double amount}) async {
|
||||
final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
|
||||
final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
|
||||
await ioniaApi.chargeGiftCard(
|
||||
username: username,
|
||||
password: password,
|
||||
@@ -154,19 +154,19 @@ class IoniaService {
|
||||
|
||||
// Get Gift Card
|
||||
|
||||
Future<IoniaGiftCard> getGiftCard({@required int id}) async {
|
||||
final username = await secureStorage.read(key: ioniaUsernameStorageKey);
|
||||
final password = await secureStorage.read(key: ioniaPasswordStorageKey);
|
||||
Future<IoniaGiftCard> getGiftCard({required int id}) async {
|
||||
final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
|
||||
final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
|
||||
return ioniaApi.getGiftCard(username: username, password: password, clientId: clientId,id: id);
|
||||
}
|
||||
|
||||
// Payment Status
|
||||
|
||||
Future<int> getPaymentStatus({
|
||||
@required String orderId,
|
||||
@required String paymentId}) async {
|
||||
final username = await secureStorage.read(key: ioniaUsernameStorageKey);
|
||||
final password = await secureStorage.read(key: ioniaPasswordStorageKey);
|
||||
required String orderId,
|
||||
required String paymentId}) async {
|
||||
final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
|
||||
final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
|
||||
return ioniaApi.getPaymentStatus(username: username, password: password, clientId: clientId, orderId: orderId, paymentId: paymentId);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,13 @@
|
||||
class IoniaTip {
|
||||
const IoniaTip({this.originalAmount, this.percentage});
|
||||
const IoniaTip({
|
||||
required this.originalAmount,
|
||||
required this.percentage,
|
||||
this.isCustom = false});
|
||||
|
||||
final double originalAmount;
|
||||
final double percentage;
|
||||
final bool isCustom;
|
||||
|
||||
double get additionalAmount => double.parse((originalAmount * percentage / 100).toStringAsFixed(2));
|
||||
|
||||
static const tipList = [
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class IoniaTokenData {
|
||||
IoniaTokenData({@required this.accessToken, @required this.tokenType, @required this.expiredAt});
|
||||
IoniaTokenData({required this.accessToken, required this.tokenType, required this.expiredAt});
|
||||
|
||||
factory IoniaTokenData.fromJson(String source) {
|
||||
final decoded = json.decode(source) as Map<String, dynamic>;
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class IoniaVirtualCard {
|
||||
IoniaVirtualCard({
|
||||
@required this.token,
|
||||
@required this.createdAt,
|
||||
@required this.lastFour,
|
||||
@required this.state,
|
||||
@required this.pan,
|
||||
@required this.cvv,
|
||||
@required this.expirationMonth,
|
||||
@required this.expirationYear,
|
||||
@required this.fundsLimit,
|
||||
@required this.spendLimit});
|
||||
required this.token,
|
||||
required this.createdAt,
|
||||
required this.lastFour,
|
||||
required this.state,
|
||||
required this.pan,
|
||||
required this.cvv,
|
||||
required this.expirationMonth,
|
||||
required this.expirationYear,
|
||||
required this.fundsLimit,
|
||||
required this.spendLimit});
|
||||
|
||||
factory IoniaVirtualCard.fromMap(Map<String, Object> source) {
|
||||
factory IoniaVirtualCard.fromMap(Map<String, dynamic> source) {
|
||||
final created = source['created'] as String;
|
||||
final createdAt = DateTime.tryParse(created);
|
||||
|
||||
@@ -37,7 +35,7 @@ class IoniaVirtualCard {
|
||||
final String cvv;
|
||||
final String expirationMonth;
|
||||
final String expirationYear;
|
||||
final DateTime createdAt;
|
||||
final DateTime? createdAt;
|
||||
final double fundsLimit;
|
||||
final double spendLimit;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user