mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-23 06:38:35 +02:00
Merge branch 'main' into CW-529-Modify-2FA-introduction-screens
This commit is contained in:
@@ -2,11 +2,11 @@ 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.title, required this.content});
|
||||
|
||||
final BuyProviderDescription description;
|
||||
final String text;
|
||||
final String title;
|
||||
final String content;
|
||||
|
||||
@override
|
||||
String toString() => '${description.title}: $text';
|
||||
String toString() => '$title: $content';
|
||||
}
|
||||
+20
-12
@@ -1,27 +1,35 @@
|
||||
import 'package:cake_wallet/buy/buy_amount.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider_description.dart';
|
||||
import 'package:cake_wallet/buy/order.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
abstract class BuyProvider {
|
||||
BuyProvider({required this.wallet, required this.isTestEnvironment});
|
||||
BuyProvider({
|
||||
required this.wallet,
|
||||
required this.isTestEnvironment,
|
||||
});
|
||||
|
||||
final WalletBase wallet;
|
||||
final bool isTestEnvironment;
|
||||
|
||||
String get title;
|
||||
BuyProviderDescription get description;
|
||||
String get trackUrl;
|
||||
|
||||
WalletType get walletType => wallet.type;
|
||||
String get walletAddress => wallet.walletAddresses.address;
|
||||
String get walletId => wallet.id;
|
||||
String get buyOptionDescription;
|
||||
|
||||
String get sellOptionDescription;
|
||||
|
||||
String get lightIcon;
|
||||
|
||||
String get darkIcon;
|
||||
|
||||
@override
|
||||
String toString() => title;
|
||||
|
||||
Future<String> requestUrl(String amount, String sourceCurrency);
|
||||
Future<Order> findOrderById(String id);
|
||||
Future<BuyAmount> calculateAmount(String amount, String sourceCurrency);
|
||||
}
|
||||
Future<void> launchProvider(BuildContext context, bool? isBuyAction);
|
||||
|
||||
Future<String> requestUrl(String amount, String sourceCurrency) => throw UnimplementedError();
|
||||
|
||||
Future<Order> findOrderById(String id) => throw UnimplementedError();
|
||||
|
||||
Future<BuyAmount> calculateAmount(String amount, String sourceCurrency) => throw UnimplementedError();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
@@ -11,10 +12,9 @@ import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class DFXBuyProvider {
|
||||
DFXBuyProvider({required WalletBase wallet}) : this._wallet = wallet;
|
||||
|
||||
final WalletBase _wallet;
|
||||
class DFXBuyProvider extends BuyProvider {
|
||||
DFXBuyProvider({required WalletBase wallet, bool isTestEnvironment = false})
|
||||
: super(wallet: wallet, isTestEnvironment: isTestEnvironment);
|
||||
|
||||
static const _baseUrl = 'api.dfx.swiss';
|
||||
static const _authPath = '/v1/auth/signMessage';
|
||||
@@ -22,8 +22,23 @@ class DFXBuyProvider {
|
||||
static const _signInPath = '/v1/auth/signIn';
|
||||
static const walletName = 'CakeWallet';
|
||||
|
||||
@override
|
||||
String get title => 'DFX Connect';
|
||||
|
||||
@override
|
||||
String get buyOptionDescription => S.current.dfx_option_description;
|
||||
|
||||
@override
|
||||
String get sellOptionDescription => S.current.dfx_option_description;
|
||||
|
||||
@override
|
||||
String get lightIcon => 'assets/images/dfx_light.png';
|
||||
|
||||
@override
|
||||
String get darkIcon => 'assets/images/dfx_dark.png';
|
||||
|
||||
String get assetOut {
|
||||
switch (_wallet.type) {
|
||||
switch (wallet.type) {
|
||||
case WalletType.bitcoin:
|
||||
return 'BTC';
|
||||
case WalletType.bitcoinCash:
|
||||
@@ -35,12 +50,12 @@ class DFXBuyProvider {
|
||||
case WalletType.ethereum:
|
||||
return 'ETH';
|
||||
default:
|
||||
throw Exception("WalletType is not available for DFX ${_wallet.type}");
|
||||
throw Exception("WalletType is not available for DFX ${wallet.type}");
|
||||
}
|
||||
}
|
||||
|
||||
String get blockchain {
|
||||
switch (_wallet.type) {
|
||||
switch (wallet.type) {
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.bitcoinCash:
|
||||
case WalletType.litecoin:
|
||||
@@ -50,12 +65,12 @@ class DFXBuyProvider {
|
||||
case WalletType.ethereum:
|
||||
return 'Ethereum';
|
||||
default:
|
||||
throw Exception("WalletType is not available for DFX ${_wallet.type}");
|
||||
throw Exception("WalletType is not available for DFX ${wallet.type}");
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getSignMessage() async {
|
||||
final walletAddress = _wallet.walletAddresses.address;
|
||||
final walletAddress = wallet.walletAddresses.address;
|
||||
final uri = Uri.https(_baseUrl, _authPath, {'address': walletAddress});
|
||||
|
||||
var response = await http.get(uri, headers: {'accept': 'application/json'});
|
||||
@@ -71,7 +86,7 @@ class DFXBuyProvider {
|
||||
|
||||
Future<String> signUp() async {
|
||||
final signMessage = getSignature(await getSignMessage());
|
||||
final walletAddress = _wallet.walletAddresses.address;
|
||||
final walletAddress = wallet.walletAddresses.address;
|
||||
|
||||
final requestBody = jsonEncode({
|
||||
'wallet': walletName,
|
||||
@@ -86,6 +101,10 @@ class DFXBuyProvider {
|
||||
if (response.statusCode == 201) {
|
||||
final responseBody = jsonDecode(response.body);
|
||||
return responseBody['accessToken'] as String;
|
||||
} else if (response.statusCode == 403) {
|
||||
final responseBody = jsonDecode(response.body);
|
||||
final message = responseBody['message'] ?? 'Service unavailable in your country';
|
||||
throw Exception(message);
|
||||
} else {
|
||||
throw Exception(
|
||||
'Failed to sign up. Status: ${response.statusCode} ${response.body}');
|
||||
@@ -94,7 +113,7 @@ class DFXBuyProvider {
|
||||
|
||||
Future<String> signIn() async {
|
||||
final signMessage = getSignature(await getSignMessage());
|
||||
final walletAddress = _wallet.walletAddresses.address;
|
||||
final walletAddress = wallet.walletAddresses.address;
|
||||
|
||||
final requestBody = jsonEncode({
|
||||
'address': walletAddress,
|
||||
@@ -108,6 +127,10 @@ class DFXBuyProvider {
|
||||
if (response.statusCode == 201) {
|
||||
final responseBody = jsonDecode(response.body);
|
||||
return responseBody['accessToken'] as String;
|
||||
} else if (response.statusCode == 403) {
|
||||
final responseBody = jsonDecode(response.body);
|
||||
final message = responseBody['message'] ?? 'Service unavailable in your country';
|
||||
throw Exception(message);
|
||||
} else {
|
||||
throw Exception(
|
||||
'Failed to sign in. Status: ${response.statusCode} ${response.body}');
|
||||
@@ -115,24 +138,25 @@ class DFXBuyProvider {
|
||||
}
|
||||
|
||||
String getSignature(String message) {
|
||||
switch (_wallet.type) {
|
||||
switch (wallet.type) {
|
||||
case WalletType.ethereum:
|
||||
return _wallet.signMessage(message);
|
||||
return wallet.signMessage(message);
|
||||
case WalletType.monero:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.bitcoinCash:
|
||||
return _wallet.signMessage(message,
|
||||
address: _wallet.walletAddresses.address);
|
||||
return wallet.signMessage(message,
|
||||
address: wallet.walletAddresses.address);
|
||||
default:
|
||||
throw Exception("WalletType is not available for DFX ${_wallet.type}");
|
||||
throw Exception("WalletType is not available for DFX ${wallet.type}");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> launchProvider(BuildContext context) async {
|
||||
Future<void> launchProvider(BuildContext context, bool? isBuyAction) async {
|
||||
try {
|
||||
final assetOut = this.assetOut;
|
||||
final blockchain = this.blockchain;
|
||||
final actionType = isBuyAction == true ? '/buy' : '/sell';
|
||||
|
||||
String accessToken;
|
||||
|
||||
@@ -146,7 +170,7 @@ class DFXBuyProvider {
|
||||
}
|
||||
}
|
||||
|
||||
final uri = Uri.https('services.dfx.swiss', '/buy', {
|
||||
final uri = Uri.https('services.dfx.swiss', actionType, {
|
||||
'session': accessToken,
|
||||
'lang': 'en',
|
||||
'asset-out': assetOut,
|
||||
@@ -156,8 +180,8 @@ class DFXBuyProvider {
|
||||
|
||||
if (await canLaunchUrl(uri)) {
|
||||
if (DeviceInfo.instance.isMobile) {
|
||||
Navigator.of(context).pushNamed(Routes.webViewPage,
|
||||
arguments: [S.of(context).buy, uri]);
|
||||
Navigator.of(context)
|
||||
.pushNamed(Routes.webViewPage, arguments: ["DFX Connect", uri]);
|
||||
} else {
|
||||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import 'dart:convert';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:cake_wallet/buy/buy_exception.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cake_wallet/buy/buy_amount.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
@@ -14,33 +19,41 @@ import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class MoonPaySellProvider {
|
||||
MoonPaySellProvider({this.isTest = false})
|
||||
: baseUrl = isTest ? _baseTestUrl : _baseProductUrl;
|
||||
MoonPaySellProvider({required SettingsStore settingsStore,
|
||||
required WalletBase wallet, this.isTest = false})
|
||||
: baseUrl = isTest ? _baseTestUrl : _baseProductUrl,
|
||||
this._settingsStore = settingsStore,
|
||||
this._wallet = wallet;
|
||||
|
||||
final SettingsStore _settingsStore;
|
||||
final WalletBase _wallet;
|
||||
|
||||
static const _baseTestUrl = 'sell-sandbox.moonpay.com';
|
||||
static const _baseProductUrl = 'sell.moonpay.com';
|
||||
|
||||
static String themeToMoonPayTheme(ThemeBase theme) {
|
||||
switch (theme.type) {
|
||||
case ThemeType.bright:
|
||||
return 'light';
|
||||
case ThemeType.light:
|
||||
return 'light';
|
||||
case ThemeType.dark:
|
||||
return 'dark';
|
||||
}
|
||||
}
|
||||
static String get _apiKey => secrets.moonPayApiKey;
|
||||
static String get _secretKey => secrets.moonPaySecretKey;
|
||||
|
||||
static String get _apiKey => secrets.moonPayApiKey;
|
||||
static String get _secretKey => secrets.moonPaySecretKey;
|
||||
final bool isTest;
|
||||
final String baseUrl;
|
||||
|
||||
Future<Uri> requestUrl(
|
||||
{required CryptoCurrency currency,
|
||||
required String refundWalletAddress,
|
||||
required SettingsStore settingsStore}) async {
|
||||
|
||||
Future<Uri> requestUrl({
|
||||
required CryptoCurrency currency,
|
||||
required String refundWalletAddress,
|
||||
required SettingsStore settingsStore,
|
||||
}) async {
|
||||
final customParams = {
|
||||
'theme': themeToMoonPayTheme(settingsStore.currentTheme),
|
||||
'language': settingsStore.languageCode,
|
||||
@@ -50,11 +63,15 @@ class MoonPaySellProvider {
|
||||
};
|
||||
|
||||
final originalUri = Uri.https(
|
||||
baseUrl, '', <String, dynamic>{
|
||||
baseUrl,
|
||||
'',
|
||||
<String, dynamic>{
|
||||
'apiKey': _apiKey,
|
||||
'defaultBaseCurrencyCode': currency.toString().toLowerCase(),
|
||||
'refundWalletAddress': refundWalletAddress
|
||||
}..addAll(customParams));
|
||||
'refundWalletAddress': refundWalletAddress,
|
||||
}..addAll(customParams),
|
||||
);
|
||||
|
||||
final messageBytes = utf8.encode('?${originalUri.query}');
|
||||
final key = utf8.encode(_secretKey);
|
||||
final hmac = Hmac(sha256, key);
|
||||
@@ -70,6 +87,38 @@ class MoonPaySellProvider {
|
||||
final signedUri = originalUri.replace(queryParameters: query);
|
||||
return signedUri;
|
||||
}
|
||||
|
||||
Future<void> launchProvider(BuildContext context) async {
|
||||
try {
|
||||
final uri = await requestUrl(
|
||||
currency: _wallet.currency,
|
||||
refundWalletAddress: _wallet.walletAddresses.address,
|
||||
settingsStore: _settingsStore,
|
||||
);
|
||||
|
||||
if (await canLaunchUrl(uri)) {
|
||||
if (DeviceInfo.instance.isMobile) {
|
||||
Navigator.of(context).pushNamed(Routes.webViewPage, arguments: ['MoonPay', uri]);
|
||||
} else {
|
||||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||
}
|
||||
} else {
|
||||
throw Exception('Could not launch URL');
|
||||
}
|
||||
} catch (e) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: 'MoonPay',
|
||||
alertContent: 'The MoonPay service is currently unavailable: $e',
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MoonPayBuyProvider extends BuyProvider {
|
||||
@@ -88,20 +137,24 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||
static const _secretKey = secrets.moonPaySecretKey;
|
||||
|
||||
@override
|
||||
String get title => 'MoonPay';
|
||||
String get title => 'Moon Pay';
|
||||
|
||||
@override
|
||||
BuyProviderDescription get description => BuyProviderDescription.moonPay;
|
||||
String get buyOptionDescription => '';
|
||||
|
||||
@override
|
||||
String get lightIcon => 'assets/images/moonpay_light.png';
|
||||
|
||||
@override
|
||||
String get darkIcon => 'assets/images/moonpay_dark.png';
|
||||
|
||||
String get currencyCode =>
|
||||
walletTypeToCryptoCurrency(walletType).title.toLowerCase();
|
||||
walletTypeToCryptoCurrency(wallet.type).title.toLowerCase();
|
||||
|
||||
@override
|
||||
String get trackUrl => baseUrl + '/transaction_receipt?transactionId=';
|
||||
|
||||
String baseUrl;
|
||||
|
||||
@override
|
||||
Future<String> requestUrl(String amount, String sourceCurrency) async {
|
||||
final enabledPaymentMethods =
|
||||
'credit_debit_card%2Capple_pay%2Cgoogle_pay%2Csamsung_pay'
|
||||
@@ -109,7 +162,7 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||
|
||||
final suffix = '?apiKey=' + _apiKey + '¤cyCode=' +
|
||||
currencyCode + '&enabledPaymentMethods=' + enabledPaymentMethods +
|
||||
'&walletAddress=' + walletAddress +
|
||||
'&walletAddress=' + wallet.walletAddresses.address +
|
||||
'&baseCurrencyCode=' + sourceCurrency.toLowerCase() +
|
||||
'&baseCurrencyAmount=' + amount + '&lockAmount=true' +
|
||||
'&showAllCurrencies=false' + '&showWalletAddressForm=false';
|
||||
@@ -127,7 +180,6 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||
return isTestEnvironment ? originalUrl : urlWithSignature;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<BuyAmount> calculateAmount(String amount, String sourceCurrency) async {
|
||||
final url = _apiUrl + _currenciesSuffix + '/$currencyCode' +
|
||||
_quoteSuffix + '/?apiKey=' + _apiKey +
|
||||
@@ -138,8 +190,8 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw BuyException(
|
||||
description: description,
|
||||
text: 'Quote is not found!');
|
||||
title: buyOptionDescription,
|
||||
content: 'Quote is not found!');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
@@ -153,7 +205,6 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||
minAmount: minSourceAmount);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Order> findOrderById(String id) async {
|
||||
final url = _apiUrl + _transactionsSuffix + '/$id' +
|
||||
'?apiKey=' + _apiKey;
|
||||
@@ -162,8 +213,8 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw BuyException(
|
||||
description: description,
|
||||
text: 'Transaction $id is not found!');
|
||||
title: buyOptionDescription,
|
||||
content: 'Transaction $id is not found!');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
@@ -175,13 +226,13 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||
|
||||
return Order(
|
||||
id: id,
|
||||
provider: description,
|
||||
provider: BuyProviderDescription.moonPay,
|
||||
transferId: id,
|
||||
state: state,
|
||||
createdAt: createdAt,
|
||||
amount: amount.toString(),
|
||||
receiveAddress: walletAddress,
|
||||
walletId: walletId
|
||||
receiveAddress: wallet.walletAddresses.address,
|
||||
walletId: wallet.id
|
||||
);
|
||||
}
|
||||
|
||||
@@ -201,4 +252,14 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||
|
||||
return isBuyEnable;
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement sellOptionDescription
|
||||
String get sellOptionDescription => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future<void> launchProvider(BuildContext context, bool? isBuyAction) {
|
||||
// TODO: implement launchProvider
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
@@ -9,20 +10,34 @@ import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class OnRamperBuyProvider {
|
||||
OnRamperBuyProvider({required SettingsStore settingsStore, required WalletBase wallet})
|
||||
: this._settingsStore = settingsStore,
|
||||
this._wallet = wallet;
|
||||
|
||||
final SettingsStore _settingsStore;
|
||||
final WalletBase _wallet;
|
||||
class OnRamperBuyProvider extends BuyProvider {
|
||||
OnRamperBuyProvider(this._settingsStore,
|
||||
{required WalletBase wallet, bool isTestEnvironment = false})
|
||||
: super(wallet: wallet, isTestEnvironment: isTestEnvironment);
|
||||
|
||||
static const _baseUrl = 'buy.onramper.com';
|
||||
|
||||
final SettingsStore _settingsStore;
|
||||
|
||||
@override
|
||||
String get title => 'Onramper';
|
||||
|
||||
@override
|
||||
String get buyOptionDescription => S.current.onramper_option_description;
|
||||
|
||||
@override
|
||||
String get sellOptionDescription => S.current.onramper_option_description;
|
||||
|
||||
@override
|
||||
String get lightIcon => 'assets/images/onramper_light.png';
|
||||
|
||||
@override
|
||||
String get darkIcon => 'assets/images/onramper_dark.png';
|
||||
|
||||
String get _apiKey => secrets.onramperApiKey;
|
||||
|
||||
String get _normalizeCryptoCurrency {
|
||||
switch (_wallet.currency) {
|
||||
switch (wallet.currency) {
|
||||
case CryptoCurrency.ltc:
|
||||
return "LTC_LITECOIN";
|
||||
case CryptoCurrency.xmr:
|
||||
@@ -32,7 +47,7 @@ class OnRamperBuyProvider {
|
||||
case CryptoCurrency.nano:
|
||||
return "XNO_NANO";
|
||||
default:
|
||||
return _wallet.currency.title;
|
||||
return wallet.currency.title;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +55,7 @@ class OnRamperBuyProvider {
|
||||
return color.value.toRadixString(16).replaceAll(RegExp(r'^ff'), "");
|
||||
}
|
||||
|
||||
Uri requestUrl(BuildContext context) {
|
||||
Uri requestOnramperUrl(BuildContext context) {
|
||||
String primaryColor,
|
||||
secondaryColor,
|
||||
primaryTextColor,
|
||||
@@ -50,9 +65,10 @@ class OnRamperBuyProvider {
|
||||
|
||||
primaryColor = getColorStr(Theme.of(context).primaryColor);
|
||||
secondaryColor = getColorStr(Theme.of(context).colorScheme.background);
|
||||
primaryTextColor = getColorStr(Theme.of(context).extension<CakeTextTheme>()!.titleColor);
|
||||
secondaryTextColor =
|
||||
getColorStr(Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor);
|
||||
primaryTextColor =
|
||||
getColorStr(Theme.of(context).extension<CakeTextTheme>()!.titleColor);
|
||||
secondaryTextColor = getColorStr(
|
||||
Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor);
|
||||
containerColor = getColorStr(Theme.of(context).colorScheme.background);
|
||||
cardColor = getColorStr(Theme.of(context).cardColor);
|
||||
|
||||
@@ -60,12 +76,13 @@ class OnRamperBuyProvider {
|
||||
cardColor = getColorStr(Colors.white);
|
||||
}
|
||||
|
||||
final networkName = _wallet.currency.fullName?.toUpperCase().replaceAll(" ", "");
|
||||
final networkName =
|
||||
wallet.currency.fullName?.toUpperCase().replaceAll(" ", "");
|
||||
|
||||
return Uri.https(_baseUrl, '', <String, dynamic>{
|
||||
'apiKey': _apiKey,
|
||||
'defaultCrypto': _normalizeCryptoCurrency,
|
||||
'networkWallets': '${networkName}:${_wallet.walletAddresses.address}',
|
||||
'networkWallets': '${networkName}:${wallet.walletAddresses.address}',
|
||||
'supportSell': "false",
|
||||
'supportSwap': "false",
|
||||
'primaryColor': primaryColor,
|
||||
@@ -77,10 +94,11 @@ class OnRamperBuyProvider {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> launchProvider(BuildContext context) async {
|
||||
final uri = requestUrl(context);
|
||||
Future<void> launchProvider(BuildContext context, bool? isBuyAction) async {
|
||||
final uri = requestOnramperUrl(context);
|
||||
if (DeviceInfo.instance.isMobile) {
|
||||
Navigator.of(context).pushNamed(Routes.webViewPage, arguments: [S.of(context).buy, uri]);
|
||||
Navigator.of(context)
|
||||
.pushNamed(Routes.webViewPage, arguments: [S.of(context).buy, uri]);
|
||||
} else {
|
||||
await launchUrl(uri);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/buy/buy_amount.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider_description.dart';
|
||||
import 'package:cake_wallet/buy/order.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
@@ -10,40 +14,48 @@ import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class RobinhoodBuyProvider {
|
||||
RobinhoodBuyProvider({required WalletBase wallet}) : this._wallet = wallet;
|
||||
|
||||
final WalletBase _wallet;
|
||||
class RobinhoodBuyProvider extends BuyProvider{
|
||||
RobinhoodBuyProvider({required WalletBase wallet, bool isTestEnvironment = false})
|
||||
: super(wallet: wallet, isTestEnvironment: isTestEnvironment);
|
||||
|
||||
static const _baseUrl = 'applink.robinhood.com';
|
||||
static const _cIdBaseUrl = 'exchange-helper.cakewallet.com';
|
||||
|
||||
|
||||
@override
|
||||
String get title => 'Robinhood Connect';
|
||||
|
||||
@override
|
||||
String get buyOptionDescription => S.current.robinhood_option_description;
|
||||
|
||||
@override
|
||||
String get sellOptionDescription => S.current.robinhood_option_description;
|
||||
|
||||
@override
|
||||
String get lightIcon => 'assets/images/robinhood_light.png';
|
||||
|
||||
@override
|
||||
String get darkIcon => 'assets/images/robinhood_dark.png';
|
||||
|
||||
String get _applicationId => secrets.robinhoodApplicationId;
|
||||
|
||||
String get _apiSecret => secrets.robinhoodCIdApiSecret;
|
||||
|
||||
bool get isAvailable => [
|
||||
WalletType.bitcoin,
|
||||
WalletType.bitcoinCash,
|
||||
WalletType.litecoin,
|
||||
WalletType.ethereum
|
||||
].contains(_wallet.type);
|
||||
|
||||
String getSignature(String message) {
|
||||
switch (_wallet.type) {
|
||||
switch (wallet.type) {
|
||||
case WalletType.ethereum:
|
||||
return _wallet.signMessage(message);
|
||||
return wallet.signMessage(message);
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.bitcoinCash:
|
||||
return _wallet.signMessage(message, address: _wallet.walletAddresses.address);
|
||||
return wallet.signMessage(message, address: wallet.walletAddresses.address);
|
||||
default:
|
||||
throw Exception("WalletType is not available for Robinhood ${_wallet.type}");
|
||||
throw Exception("WalletType is not available for Robinhood ${wallet.type}");
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getConnectId() async {
|
||||
final walletAddress = _wallet.walletAddresses.address;
|
||||
final walletAddress = wallet.walletAddresses.address;
|
||||
final valid_until = (DateTime.now().millisecondsSinceEpoch / 1000).round() + 10;
|
||||
final message = "$_apiSecret:${valid_until}";
|
||||
|
||||
@@ -64,22 +76,22 @@ class RobinhoodBuyProvider {
|
||||
}
|
||||
}
|
||||
|
||||
Future<Uri> requestUrl() async {
|
||||
Future<Uri> requestProviderUrl() async {
|
||||
final connectId = await getConnectId();
|
||||
final networkName = _wallet.currency.fullName?.toUpperCase().replaceAll(" ", "_");
|
||||
final networkName = wallet.currency.fullName?.toUpperCase().replaceAll(" ", "_");
|
||||
|
||||
return Uri.https(_baseUrl, '/u/connect', <String, dynamic>{
|
||||
'applicationId': _applicationId,
|
||||
'connectId': connectId,
|
||||
'walletAddress': _wallet.walletAddresses.address,
|
||||
'userIdentifier': _wallet.walletAddresses.address,
|
||||
'walletAddress': wallet.walletAddresses.address,
|
||||
'userIdentifier': wallet.walletAddresses.address,
|
||||
'supportedNetworks': networkName
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> launchProvider(BuildContext context) async {
|
||||
Future<void> launchProvider(BuildContext context, bool? isBuyAction) async {
|
||||
try {
|
||||
final uri = await requestUrl();
|
||||
final uri = await requestProviderUrl();
|
||||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||
} catch (_) {
|
||||
await showPopUp<void>(
|
||||
@@ -93,4 +105,5 @@ class RobinhoodBuyProvider {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:convert';
|
||||
import 'package:cake_wallet/buy/buy_exception.dart';
|
||||
import 'package:flutter/src/widgets/framework.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cake_wallet/buy/buy_amount.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
@@ -35,16 +36,20 @@ class WyreBuyProvider extends BuyProvider {
|
||||
String get title => 'Wyre';
|
||||
|
||||
@override
|
||||
BuyProviderDescription get description => BuyProviderDescription.wyre;
|
||||
String get buyOptionDescription => '';
|
||||
|
||||
@override
|
||||
String get lightIcon => 'assets/images/robinhood_light.png';
|
||||
|
||||
@override
|
||||
String get darkIcon => 'assets/images/robinhood_dark.png';
|
||||
|
||||
String get trackUrl => isTestEnvironment
|
||||
? _trackTestUrl
|
||||
: _trackProductUrl;
|
||||
|
||||
String baseApiUrl;
|
||||
|
||||
@override
|
||||
Future<String> requestUrl(String amount, String sourceCurrency) async {
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
final url = baseApiUrl + _ordersSuffix + _reserveSuffix +
|
||||
@@ -53,8 +58,8 @@ class WyreBuyProvider extends BuyProvider {
|
||||
final body = {
|
||||
'amount': amount,
|
||||
'sourceCurrency': sourceCurrency,
|
||||
'destCurrency': walletTypeToCryptoCurrency(walletType).title,
|
||||
'dest': walletTypeToString(walletType).toLowerCase() + ':' + walletAddress,
|
||||
'destCurrency': walletTypeToCryptoCurrency(wallet.type).title,
|
||||
'dest': walletTypeToString(wallet.type).toLowerCase() + ':' + wallet.walletAddresses.address,
|
||||
'referrerAccountId': _accountId,
|
||||
'lockFields': ['amount', 'sourceCurrency', 'destCurrency', 'dest']
|
||||
};
|
||||
@@ -68,8 +73,8 @@ class WyreBuyProvider extends BuyProvider {
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw BuyException(
|
||||
description: description,
|
||||
text: 'Url $url is not found!');
|
||||
title: buyOptionDescription,
|
||||
content: 'Url $url is not found!');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
@@ -77,14 +82,13 @@ class WyreBuyProvider extends BuyProvider {
|
||||
return urlFromResponse;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<BuyAmount> calculateAmount(String amount, String sourceCurrency) async {
|
||||
final quoteUrl = _baseProductApiUrl + _ordersSuffix + _quoteSuffix;
|
||||
final body = {
|
||||
'amount': amount,
|
||||
'sourceCurrency': sourceCurrency,
|
||||
'destCurrency': walletTypeToCryptoCurrency(walletType).title,
|
||||
'dest': walletTypeToString(walletType).toLowerCase() + ':' + walletAddress,
|
||||
'destCurrency': walletTypeToCryptoCurrency(wallet.type).title,
|
||||
'dest': walletTypeToString(wallet.type).toLowerCase() + ':' + wallet.walletAddresses.address,
|
||||
'accountId': _accountId,
|
||||
'country': _countryCode
|
||||
};
|
||||
@@ -99,8 +103,8 @@ class WyreBuyProvider extends BuyProvider {
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw BuyException(
|
||||
description: description,
|
||||
text: 'Quote is not found!');
|
||||
title: buyOptionDescription,
|
||||
content: 'Quote is not found!');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
@@ -111,7 +115,6 @@ class WyreBuyProvider extends BuyProvider {
|
||||
return BuyAmount(sourceAmount: sourceAmount, destAmount: destAmount, achSourceAmount: achAmount);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Order> findOrderById(String id) async {
|
||||
final orderUrl = baseApiUrl + _ordersSuffix + '/$id';
|
||||
final orderUri = Uri.parse(orderUrl);
|
||||
@@ -119,8 +122,8 @@ class WyreBuyProvider extends BuyProvider {
|
||||
|
||||
if (orderResponse.statusCode != 200) {
|
||||
throw BuyException(
|
||||
description: description,
|
||||
text: 'Order $id is not found!');
|
||||
title: buyOptionDescription,
|
||||
content: 'Order $id is not found!');
|
||||
}
|
||||
|
||||
final orderResponseJSON =
|
||||
@@ -141,8 +144,8 @@ class WyreBuyProvider extends BuyProvider {
|
||||
|
||||
if (transferResponse.statusCode != 200) {
|
||||
throw BuyException(
|
||||
description: description,
|
||||
text: 'Transfer $transferId is not found!');
|
||||
title: buyOptionDescription,
|
||||
content: 'Transfer $transferId is not found!');
|
||||
}
|
||||
|
||||
final transferResponseJSON =
|
||||
@@ -151,15 +154,25 @@ class WyreBuyProvider extends BuyProvider {
|
||||
|
||||
return Order(
|
||||
id: id,
|
||||
provider: description,
|
||||
provider: BuyProviderDescription.wyre,
|
||||
transferId: transferId,
|
||||
from: from,
|
||||
to: to,
|
||||
state: state,
|
||||
createdAt: createdAt,
|
||||
amount: amount.toString(),
|
||||
receiveAddress: walletAddress,
|
||||
walletId: walletId
|
||||
receiveAddress: wallet.walletAddresses.address,
|
||||
walletId: wallet.id
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> launchProvider(BuildContext context, bool? isBuyAction) {
|
||||
// TODO: implement launchProvider
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement sellOptionDescription
|
||||
String get sellOptionDescription => throw UnimplementedError();
|
||||
}
|
||||
@@ -92,7 +92,7 @@ class AddressValidator extends TextValidator {
|
||||
case CryptoCurrency.eos:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.bch:
|
||||
return '^(?!bitcoincash:)[0-9a-zA-Z]*\$|^(?!bitcoincash:)q[0-9a-zA-Z]{41}\$|^(?!bitcoincash:)q[0-9a-zA-Z]{42}\$|^bitcoincash:q[0-9a-zA-Z]{41}\$|^bitcoincash:q[0-9a-zA-Z]{42}\$';
|
||||
return '^(?!bitcoincash:)[0-9a-zA-Z]*\$|^(?!bitcoincash:)q|p[0-9a-zA-Z]{41}\$|^(?!bitcoincash:)q|p[0-9a-zA-Z]{42}\$|^bitcoincash:q|p[0-9a-zA-Z]{41}\$|^bitcoincash:q|p[0-9a-zA-Z]{42}\$';
|
||||
case CryptoCurrency.bnb:
|
||||
return '[0-9a-zA-Z]';
|
||||
case CryptoCurrency.ltc:
|
||||
|
||||
@@ -138,7 +138,7 @@ class EvmChainServiceImpl implements ChainService {
|
||||
try {
|
||||
// Load the private key
|
||||
final List<ChainKeyModel> keys = wcKeyService
|
||||
.getKeysForChain(getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type));
|
||||
.getKeysForChain(appStore.wallet!);
|
||||
|
||||
final Credentials credentials = EthPrivateKey.fromHex(keys[0].privateKey);
|
||||
|
||||
@@ -177,7 +177,7 @@ class EvmChainServiceImpl implements ChainService {
|
||||
try {
|
||||
// Load the private key
|
||||
final List<ChainKeyModel> keys = wcKeyService
|
||||
.getKeysForChain(getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type));
|
||||
.getKeysForChain(appStore.wallet!);
|
||||
|
||||
final EthPrivateKey credentials = EthPrivateKey.fromHex(keys[0].privateKey);
|
||||
|
||||
@@ -215,7 +215,7 @@ class EvmChainServiceImpl implements ChainService {
|
||||
|
||||
// Load the private key
|
||||
final List<ChainKeyModel> keys = wcKeyService
|
||||
.getKeysForChain(getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type));
|
||||
.getKeysForChain(appStore.wallet!);
|
||||
|
||||
final Credentials credentials = EthPrivateKey.fromHex(keys[0].privateKey);
|
||||
|
||||
@@ -275,7 +275,7 @@ class EvmChainServiceImpl implements ChainService {
|
||||
}
|
||||
|
||||
final List<ChainKeyModel> keys = wcKeyService
|
||||
.getKeysForChain(getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type));
|
||||
.getKeysForChain(appStore.wallet!);
|
||||
|
||||
return EthSigUtil.signTypedData(
|
||||
privateKey: keys[0].privateKey,
|
||||
|
||||
@@ -1,48 +1,22 @@
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
|
||||
import 'package:cake_wallet/polygon/polygon.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
abstract class WalletConnectKeyService {
|
||||
/// Returns a list of all the keys.
|
||||
List<ChainKeyModel> getKeys();
|
||||
|
||||
/// Returns a list of all the chain ids.
|
||||
List<String> getChains();
|
||||
List<ChainKeyModel> getKeys(WalletBase wallet);
|
||||
|
||||
/// Returns a list of all the keys for a given chain id.
|
||||
/// If the chain is not found, returns an empty list.
|
||||
/// - [chain]: The chain to get the keys for.
|
||||
List<ChainKeyModel> getKeysForChain(String chain);
|
||||
List<ChainKeyModel> getKeysForChain(WalletBase wallet);
|
||||
|
||||
/// Returns a list of all the accounts in namespace:chainId:address format.
|
||||
List<String> getAllAccounts();
|
||||
}
|
||||
|
||||
class KeyServiceImpl implements WalletConnectKeyService {
|
||||
KeyServiceImpl(this.wallet)
|
||||
: _keys = [
|
||||
ChainKeyModel(
|
||||
chains: [
|
||||
'eip155:1',
|
||||
'eip155:5',
|
||||
'eip155:137',
|
||||
'eip155:42161',
|
||||
'eip155:80001',
|
||||
],
|
||||
privateKey: _getPrivateKeyForWallet(wallet),
|
||||
publicKey: _getPublicKeyForWallet(wallet),
|
||||
),
|
||||
];
|
||||
|
||||
late final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet;
|
||||
|
||||
late final List<ChainKeyModel> _keys;
|
||||
|
||||
static String _getPrivateKeyForWallet(WalletBase wallet) {
|
||||
switch (wallet.type) {
|
||||
case WalletType.ethereum:
|
||||
@@ -64,31 +38,31 @@ class KeyServiceImpl implements WalletConnectKeyService {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> getChains() {
|
||||
final List<String> chainIds = [];
|
||||
for (final ChainKeyModel key in _keys) {
|
||||
chainIds.addAll(key.chains);
|
||||
}
|
||||
return chainIds;
|
||||
List<ChainKeyModel> getKeys(WalletBase wallet) {
|
||||
final keys = [
|
||||
ChainKeyModel(
|
||||
chains: [
|
||||
'eip155:1',
|
||||
'eip155:5',
|
||||
'eip155:137',
|
||||
'eip155:42161',
|
||||
'eip155:80001',
|
||||
],
|
||||
privateKey: _getPrivateKeyForWallet(wallet),
|
||||
publicKey: _getPublicKeyForWallet(wallet),
|
||||
),
|
||||
];
|
||||
return keys;
|
||||
}
|
||||
|
||||
@override
|
||||
List<ChainKeyModel> getKeys() => _keys;
|
||||
List<ChainKeyModel> getKeysForChain(WalletBase wallet) {
|
||||
final chain = getChainNameSpaceAndIdBasedOnWalletType(wallet.type);
|
||||
|
||||
@override
|
||||
List<ChainKeyModel> getKeysForChain(String chain) {
|
||||
return _keys.where((e) => e.chains.contains(chain)).toList();
|
||||
}
|
||||
final keys = getKeys(wallet);
|
||||
|
||||
@override
|
||||
List<String> getAllAccounts() {
|
||||
final List<String> accounts = [];
|
||||
for (final ChainKeyModel key in _keys) {
|
||||
for (final String chain in key.chains) {
|
||||
accounts.add('$chain:${key.publicKey}');
|
||||
}
|
||||
}
|
||||
return accounts;
|
||||
return keys.where((e) => e.chains.contains(chain)).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ abstract class Web3WalletServiceBase with Store {
|
||||
);
|
||||
|
||||
// Setup our accounts
|
||||
List<ChainKeyModel> chainKeys = walletKeyService.getKeys();
|
||||
List<ChainKeyModel> chainKeys = walletKeyService.getKeys(appStore.wallet!);
|
||||
for (final chainKey in chainKeys) {
|
||||
for (final chainId in chainKey.chains) {
|
||||
_web3Wallet.registerAccount(
|
||||
@@ -136,6 +136,7 @@ abstract class Web3WalletServiceBase with Store {
|
||||
_web3Wallet.onAuthRequest.unsubscribe(_onAuthRequest);
|
||||
_web3Wallet.core.pairing.onPairingDelete.unsubscribe(_onPairingDelete);
|
||||
_web3Wallet.core.pairing.onPairingExpire.unsubscribe(_onPairingDelete);
|
||||
isInitialized = false;
|
||||
}
|
||||
|
||||
Web3Wallet getWeb3Wallet() {
|
||||
@@ -236,7 +237,7 @@ abstract class Web3WalletServiceBase with Store {
|
||||
Future<void> _onAuthRequest(AuthRequest? args) async {
|
||||
if (args != null) {
|
||||
final chaindIdNamespace = getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type);
|
||||
List<ChainKeyModel> chainKeys = walletKeyService.getKeysForChain(chaindIdNamespace);
|
||||
List<ChainKeyModel> chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
|
||||
// Create the message to be signed
|
||||
final String iss = 'did:pkh:$chaindIdNamespace:${chainKeys.first.publicKey}';
|
||||
final Widget modalWidget = Web3RequestModal(
|
||||
|
||||
+13
-6
@@ -1,6 +1,7 @@
|
||||
import 'package:cake_wallet/anonpay/anonpay_api.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||
import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart';
|
||||
@@ -378,7 +379,8 @@ Future<void> setup({
|
||||
settingsStore: settingsStore,
|
||||
yatStore: getIt.get<YatStore>(),
|
||||
ordersStore: getIt.get<OrdersStore>(),
|
||||
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>()));
|
||||
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>(),
|
||||
keyService: getIt.get<KeyService>()));
|
||||
|
||||
getIt.registerFactory<AuthService>(
|
||||
() => AuthService(
|
||||
@@ -477,7 +479,7 @@ Future<void> setup({
|
||||
|
||||
final appStore = getIt.get<AppStore>();
|
||||
|
||||
getIt.registerLazySingleton<WalletConnectKeyService>(() => KeyServiceImpl(appStore.wallet!));
|
||||
getIt.registerLazySingleton<WalletConnectKeyService>(() => KeyServiceImpl());
|
||||
|
||||
getIt.registerLazySingleton<Web3WalletService>(() {
|
||||
final Web3WalletService web3WalletService = Web3WalletService(
|
||||
@@ -796,11 +798,15 @@ Future<void> setup({
|
||||
getIt.registerFactory<RobinhoodBuyProvider>(
|
||||
() => RobinhoodBuyProvider(wallet: getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory<DFXBuyProvider>(
|
||||
() => DFXBuyProvider(wallet: getIt.get<AppStore>().wallet!));
|
||||
getIt
|
||||
.registerFactory<DFXBuyProvider>(() => DFXBuyProvider(wallet: getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory<MoonPaySellProvider>(() => MoonPaySellProvider(
|
||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory<OnRamperBuyProvider>(() => OnRamperBuyProvider(
|
||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||
getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
));
|
||||
|
||||
@@ -944,7 +950,8 @@ Future<void> setup({
|
||||
|
||||
getIt.registerFactory(() => BuyAmountViewModel());
|
||||
|
||||
getIt.registerFactory(() => BuyOptionsPage(getIt.get<DashboardViewModel>()));
|
||||
getIt.registerFactoryParam<BuySellOptionsPage, bool, void>(
|
||||
(isBuyOption, _) => BuySellOptionsPage(getIt.get<DashboardViewModel>(), isBuyOption));
|
||||
|
||||
getIt.registerFactory(() {
|
||||
final wallet = getIt.get<AppStore>().wallet;
|
||||
|
||||
@@ -1,57 +1,112 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/dfx/dfx_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
enum BuyProviderType {
|
||||
AskEachTime,
|
||||
Robinhood,
|
||||
Onramper,
|
||||
DFX;
|
||||
askEachTime,
|
||||
robinhood,
|
||||
dfx,
|
||||
onramper,
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
extension BuyProviderTypeName on BuyProviderType {
|
||||
String get name {
|
||||
switch (this) {
|
||||
case BuyProviderType.AskEachTime:
|
||||
return S.current.ask_each_time;
|
||||
case BuyProviderType.Robinhood:
|
||||
return "Robinhood";
|
||||
case BuyProviderType.Onramper:
|
||||
return "Onramper";
|
||||
case BuyProviderType.DFX:
|
||||
return "DFX";
|
||||
case BuyProviderType.askEachTime:
|
||||
return 'Ask each time';
|
||||
case BuyProviderType.robinhood:
|
||||
return 'Robinhood Connect';
|
||||
case BuyProviderType.dfx:
|
||||
return 'DFX Connect';
|
||||
case BuyProviderType.onramper:
|
||||
return 'Onramper';
|
||||
default:
|
||||
return this.toString().split('.').last;
|
||||
}
|
||||
}
|
||||
|
||||
static List<BuyProviderType> getAvailableProviders(WalletType walletType) {
|
||||
String get id {
|
||||
switch (this) {
|
||||
case BuyProviderType.askEachTime:
|
||||
return 'ask_each_time_provider';
|
||||
case BuyProviderType.robinhood:
|
||||
return 'robinhood_connect_provider';
|
||||
case BuyProviderType.dfx:
|
||||
return 'dfx_connect_provider';
|
||||
case BuyProviderType.onramper:
|
||||
return 'onramper_provider';
|
||||
default:
|
||||
return this.toString().split('.').last.replaceAll('.', '_')
|
||||
.toLowerCase() + '_provider';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BuyProviderHelper {
|
||||
static List<BuyProviderType> getAvailableBuyProviderTypes(
|
||||
WalletType walletType) {
|
||||
switch (walletType) {
|
||||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
return [
|
||||
BuyProviderType.AskEachTime,
|
||||
BuyProviderType.Onramper
|
||||
];
|
||||
return [BuyProviderType.askEachTime, BuyProviderType.onramper];
|
||||
case WalletType.monero:
|
||||
return [
|
||||
BuyProviderType.AskEachTime,
|
||||
BuyProviderType.Onramper,
|
||||
BuyProviderType.DFX
|
||||
BuyProviderType.askEachTime,
|
||||
BuyProviderType.onramper,
|
||||
BuyProviderType.dfx
|
||||
];
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.ethereum:
|
||||
return [
|
||||
BuyProviderType.AskEachTime,
|
||||
BuyProviderType.Onramper,
|
||||
BuyProviderType.DFX,
|
||||
BuyProviderType.Robinhood
|
||||
BuyProviderType.askEachTime,
|
||||
BuyProviderType.onramper,
|
||||
BuyProviderType.dfx,
|
||||
BuyProviderType.robinhood
|
||||
];
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoinCash:
|
||||
return [
|
||||
BuyProviderType.AskEachTime,
|
||||
BuyProviderType.Onramper,
|
||||
BuyProviderType.Robinhood
|
||||
];
|
||||
return [
|
||||
BuyProviderType.askEachTime,
|
||||
BuyProviderType.onramper,
|
||||
BuyProviderType.robinhood
|
||||
];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
static List<BuyProviderType> getAvailableSellProviderTypes(
|
||||
WalletType walletType) {
|
||||
switch (walletType) {
|
||||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
return [BuyProviderType.askEachTime];
|
||||
case WalletType.monero:
|
||||
return [BuyProviderType.askEachTime, BuyProviderType.dfx];
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.ethereum:
|
||||
return [BuyProviderType.askEachTime, BuyProviderType.dfx];
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoinCash:
|
||||
return [BuyProviderType.askEachTime];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
static BuyProvider? getProviderByType(BuyProviderType type) {
|
||||
switch (type) {
|
||||
case BuyProviderType.robinhood:
|
||||
return getIt.get<RobinhoodBuyProvider>();
|
||||
case BuyProviderType.dfx:
|
||||
return getIt.get<DFXBuyProvider>();
|
||||
case BuyProviderType.onramper:
|
||||
return getIt.get<OnRamperBuyProvider>();
|
||||
case BuyProviderType.askEachTime:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ Future<void> loadCurrentWallet() async {
|
||||
final type = deserializeFromInt(typeRaw);
|
||||
final walletLoadingService = getIt.get<WalletLoadingService>();
|
||||
final wallet = await walletLoadingService.load(type, name);
|
||||
appStore.changeCurrentWallet(wallet);
|
||||
await appStore.changeCurrentWallet(wallet);
|
||||
|
||||
getIt.get<BackgroundTasks>().registerSyncTask();
|
||||
}
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
import 'package:cake_wallet/buy/dfx/dfx_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class MainActions {
|
||||
final String Function(BuildContext context) name;
|
||||
@@ -46,53 +37,22 @@ class MainActions {
|
||||
canShow: (viewModel) => viewModel.hasBuyAction,
|
||||
onTap: (BuildContext context, DashboardViewModel viewModel) async {
|
||||
if (!viewModel.isEnabledBuyAction) {
|
||||
await _showErrorDialog(context, S.of(context).unsupported_asset);
|
||||
await _showErrorDialog(
|
||||
context, S.of(context).buy, S.of(context).unsupported_asset);
|
||||
return;
|
||||
}
|
||||
|
||||
final defaultBuyProvider = viewModel.defaultBuyProvider;
|
||||
try {
|
||||
await _launchProviderByType(context, defaultBuyProvider);
|
||||
defaultBuyProvider != null
|
||||
? await defaultBuyProvider.launchProvider(context, true)
|
||||
: await Navigator.of(context).pushNamed(Routes.buySellPage, arguments: true);
|
||||
} catch (e) {
|
||||
await _showErrorDialog(context, e.toString());
|
||||
await _showErrorDialog(context, defaultBuyProvider.toString(), e.toString());
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
static Future<void> _launchProviderByType(BuildContext context, BuyProviderType providerType) async {
|
||||
switch (providerType) {
|
||||
case BuyProviderType.AskEachTime:
|
||||
Navigator.pushNamed(context, Routes.buy);
|
||||
break;
|
||||
case BuyProviderType.Onramper:
|
||||
await getIt.get<OnRamperBuyProvider>().launchProvider(context);
|
||||
break;
|
||||
case BuyProviderType.Robinhood:
|
||||
await getIt.get<RobinhoodBuyProvider>().launchProvider(context);
|
||||
break;
|
||||
case BuyProviderType.DFX:
|
||||
await getIt.get<DFXBuyProvider>().launchProvider(context);
|
||||
break;
|
||||
default:
|
||||
throw UnsupportedError('Unsupported buy provider type');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Future<void> _showErrorDialog(BuildContext context, String errorMessage) async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).buy,
|
||||
alertContent: errorMessage,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
static MainActions receiveAction = MainActions._(
|
||||
name: (context) => S.of(context).receive,
|
||||
image: 'assets/images/received.png',
|
||||
@@ -127,42 +87,35 @@ class MainActions {
|
||||
isEnabled: (viewModel) => viewModel.isEnabledSellAction,
|
||||
canShow: (viewModel) => viewModel.hasSellAction,
|
||||
onTap: (BuildContext context, DashboardViewModel viewModel) async {
|
||||
final walletType = viewModel.type;
|
||||
if (!viewModel.isEnabledSellAction) {
|
||||
await _showErrorDialog(
|
||||
context, S.of(context).sell, S.of(context).unsupported_asset);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (walletType) {
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.ethereum:
|
||||
case WalletType.polygon:
|
||||
case WalletType.bitcoinCash:
|
||||
if (viewModel.isEnabledSellAction) {
|
||||
final moonPaySellProvider = MoonPaySellProvider();
|
||||
final uri = await moonPaySellProvider.requestUrl(
|
||||
currency: viewModel.wallet.currency,
|
||||
refundWalletAddress: viewModel.wallet.walletAddresses.address,
|
||||
settingsStore: viewModel.settingsStore,
|
||||
);
|
||||
if (DeviceInfo.instance.isMobile) {
|
||||
Navigator.of(context).pushNamed(Routes.webViewPage,
|
||||
arguments: [S.of(context).sell, uri]);
|
||||
} else {
|
||||
await launchUrl(uri);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).sell,
|
||||
alertContent: S.of(context).unsupported_asset,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
},
|
||||
);
|
||||
final defaultSellProvider = viewModel.defaultSellProvider;
|
||||
try {
|
||||
defaultSellProvider != null
|
||||
? await defaultSellProvider.launchProvider(context, false)
|
||||
: await Navigator.of(context).pushNamed(Routes.buySellPage, arguments: false);
|
||||
} catch (e) {
|
||||
await _showErrorDialog(context, defaultSellProvider.toString(), e.toString());
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> _showErrorDialog(
|
||||
BuildContext context, String title, String errorMessage) async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: title,
|
||||
alertContent: errorMessage,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -390,8 +390,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => getIt.get<OrderDetailsPage>(param1: settings.arguments as Order));
|
||||
|
||||
case Routes.buy:
|
||||
return MaterialPageRoute<void>(builder: (_) => getIt.get<BuyOptionsPage>());
|
||||
case Routes.buySellPage:
|
||||
final args = settings.arguments as bool;
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => getIt.get<BuySellOptionsPage>(param1: args));
|
||||
|
||||
case Routes.buyWebView:
|
||||
final args = settings.arguments as List;
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ class Routes {
|
||||
static const supportLiveChat = '/support/live_chat';
|
||||
static const supportOtherLinks = '/support/other';
|
||||
static const orderDetails = '/order_details';
|
||||
static const buy = '/buy';
|
||||
static const buySellPage = '/buy_sell_page';
|
||||
static const buyWebView = '/buy_web_view';
|
||||
static const unspentCoinsList = '/unspent_coins_list';
|
||||
static const unspentCoinsDetails = '/unspent_coins_details';
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import 'package:cake_wallet/buy/dfx/dfx_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
@@ -11,19 +8,14 @@ import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BuyOptionsPage extends BasePage {
|
||||
BuyOptionsPage(this.dashboardViewModel);
|
||||
class BuySellOptionsPage extends BasePage {
|
||||
BuySellOptionsPage(this.dashboardViewModel, this.isBuyAction);
|
||||
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
final iconDarkRobinhood = 'assets/images/robinhood_dark.png';
|
||||
final iconLightRobinhood = 'assets/images/robinhood_light.png';
|
||||
final iconDarkOnramper = 'assets/images/onramper_dark.png';
|
||||
final iconLightOnramper = 'assets/images/onramper_light.png';
|
||||
final iconDarkDFX = 'assets/images/dfx_dark.png';
|
||||
final iconLightDFX = 'assets/images/dfx_light.png';
|
||||
final bool isBuyAction;
|
||||
|
||||
@override
|
||||
String get title => S.current.buy;
|
||||
String get title => isBuyAction ? S.current.buy : S.current.sell;
|
||||
|
||||
@override
|
||||
AppBarStyle get appBarStyle => AppBarStyle.regular;
|
||||
@@ -32,17 +24,9 @@ class BuyOptionsPage extends BasePage {
|
||||
Widget body(BuildContext context) {
|
||||
final isLightMode =
|
||||
Theme.of(context).extension<OptionTileTheme>()?.useDarkImage ?? false;
|
||||
final iconRobinhood = Image.asset(
|
||||
isLightMode ? iconLightRobinhood : iconDarkRobinhood,
|
||||
height: 40,
|
||||
width: 40);
|
||||
final iconOnramper = Image.asset(
|
||||
isLightMode ? iconLightOnramper : iconDarkOnramper,
|
||||
height: 40,
|
||||
width: 40);
|
||||
final iconDFX = Image.asset(isLightMode ? iconLightDFX : iconDarkDFX,
|
||||
height: 40, width: 40);
|
||||
final availableProviders = dashboardViewModel.availableProviders;
|
||||
final availableProviders = isBuyAction
|
||||
? dashboardViewModel.availableBuyProviders
|
||||
: dashboardViewModel.availableSellProviders;
|
||||
|
||||
return Container(
|
||||
child: Center(
|
||||
@@ -50,57 +34,43 @@ class BuyOptionsPage extends BasePage {
|
||||
constraints: BoxConstraints(maxWidth: 330),
|
||||
child: Column(
|
||||
children: [
|
||||
if (availableProviders.contains(BuyProviderType.Onramper))
|
||||
Padding(
|
||||
...availableProviders.map((provider) {
|
||||
final icon = Image.asset(
|
||||
isLightMode ? provider.lightIcon : provider.darkIcon,
|
||||
height: 40,
|
||||
width: 40,
|
||||
);
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
image: iconOnramper,
|
||||
title: "Onramper",
|
||||
description: S.of(context).onramper_option_description,
|
||||
onPressed: () async => await getIt
|
||||
.get<OnRamperBuyProvider>()
|
||||
.launchProvider(context),
|
||||
image: icon,
|
||||
title: provider.toString(),
|
||||
description: isBuyAction
|
||||
? provider.buyOptionDescription
|
||||
: provider.sellOptionDescription,
|
||||
onPressed: () =>
|
||||
provider.launchProvider(context, isBuyAction),
|
||||
),
|
||||
),
|
||||
if (availableProviders.contains(BuyProviderType.Robinhood))
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
image: iconRobinhood,
|
||||
title: "Robinhood Connect",
|
||||
description: S.of(context).robinhood_option_description,
|
||||
onPressed: () async => await getIt
|
||||
.get<RobinhoodBuyProvider>()
|
||||
.launchProvider(context),
|
||||
),
|
||||
),
|
||||
if (availableProviders.contains(BuyProviderType.DFX))
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
image: iconDFX,
|
||||
title: "DFX Connect",
|
||||
description: S.of(context).dfx_option_description,
|
||||
onPressed: () async => await getIt
|
||||
.get<DFXBuyProvider>()
|
||||
.launchProvider(context),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
Spacer(),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
|
||||
child: Text(
|
||||
S.of(context).select_buy_provider_notice,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context)
|
||||
.extension<TransactionTradeTheme>()!
|
||||
.detailsTitlesColor,
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
|
||||
child: Text(
|
||||
isBuyAction
|
||||
? S.of(context).select_buy_provider_notice
|
||||
: S.of(context).select_sell_provider_notice,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context)
|
||||
.extension<TransactionTradeTheme>()!
|
||||
.detailsTitlesColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -29,11 +29,10 @@ class BuyListItem extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isSelected = selectedProvider?.description == provider.description;
|
||||
final isSelected = selectedProvider?.buyOptionDescription == provider.buyOptionDescription;
|
||||
final iconColor = isSelected ? Colors.white : Colors.black;
|
||||
|
||||
final providerIcon = getBuyProviderIcon(provider.description,
|
||||
iconColor: iconColor)!;
|
||||
final providerIcon = Image.asset('assets/images/wyre-icon.png', width: 36, height: 36);
|
||||
|
||||
final backgroundColor = isSelected
|
||||
? Palette.greyBlueCraiola
|
||||
@@ -76,7 +75,7 @@ class BuyListItem extends StatelessWidget {
|
||||
padding: EdgeInsets.only(right: 10),
|
||||
child: providerIcon),
|
||||
Text(
|
||||
provider.description.title,
|
||||
provider.title,
|
||||
style: TextStyle(
|
||||
color: secondaryTextColor,
|
||||
fontSize: 20,
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sideba
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
|
||||
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||
import 'package:cake_wallet/src/widgets/vulnerable_seeds_popup.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/version_comparator.dart';
|
||||
@@ -60,7 +61,8 @@ class DashboardPage extends StatelessWidget {
|
||||
);
|
||||
|
||||
if (DeviceInfo.instance.isDesktop) {
|
||||
if (responsiveLayoutUtil.screenWidth > ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
|
||||
if (responsiveLayoutUtil.screenWidth >
|
||||
ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
|
||||
return getIt.get<DesktopSidebarWrapper>();
|
||||
} else {
|
||||
return dashboardPageView;
|
||||
@@ -295,6 +297,8 @@ class _DashboardPageView extends BasePage {
|
||||
|
||||
_showReleaseNotesPopup(context);
|
||||
|
||||
_showVulnerableSeedsPopup(context);
|
||||
|
||||
var needToPresentYat = false;
|
||||
var isInactive = false;
|
||||
|
||||
@@ -354,4 +358,22 @@ class _DashboardPageView extends BasePage {
|
||||
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
|
||||
}
|
||||
}
|
||||
|
||||
void _showVulnerableSeedsPopup(BuildContext context) async {
|
||||
final List<String> affectedWalletNames = await dashboardViewModel.checkAffectedWallets();
|
||||
|
||||
if (affectedWalletNames.isNotEmpty) {
|
||||
Future<void>.delayed(
|
||||
Duration(seconds: 1),
|
||||
() {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return VulnerableSeedsPopup(affectedWalletNames);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart';
|
||||
import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
|
||||
import 'package:cake_wallet/src/widgets/vulnerable_seeds_popup.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/utils/version_comparator.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -110,5 +111,25 @@ class DesktopDashboardPage extends StatelessWidget {
|
||||
} else if (isNewInstall!) {
|
||||
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
|
||||
}
|
||||
|
||||
_showVulnerableSeedsPopup(context);
|
||||
}
|
||||
|
||||
void _showVulnerableSeedsPopup(BuildContext context) async {
|
||||
final List<String> affectedWalletNames = await dashboardViewModel.checkAffectedWallets();
|
||||
|
||||
if (affectedWalletNames.isNotEmpty) {
|
||||
Future<void>.delayed(
|
||||
Duration(seconds: 1),
|
||||
() {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return VulnerableSeedsPopup(affectedWalletNames);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,24 @@ class BalancePage extends StatelessWidget {
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
height: 1,
|
||||
),
|
||||
unselectedLabelStyle: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
height: 1,
|
||||
),
|
||||
labelColor:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
dividerColor:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
indicatorColor:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
unselectedLabelColor: Theme.of(context)
|
||||
.extension<DashboardPageTheme>()!
|
||||
.pageTitleTextColor
|
||||
.withOpacity(0.5),
|
||||
tabs: [
|
||||
Tab(text: 'My Crypto'),
|
||||
Tab(text: 'My NFTs'),
|
||||
|
||||
@@ -411,10 +411,6 @@ class ExchangePage extends BasePage {
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => exchangeViewModel.isReceiveAddressEnabled, (bool isEnabled) {
|
||||
receiveKey.currentState!.isAddressEditable(isEditable: isEnabled);
|
||||
});
|
||||
|
||||
reaction((_) => exchangeViewModel.isReceiveAmountEditable, (bool isReceiveAmountEditable) {
|
||||
receiveKey.currentState!.isAmountEditable(isEditable: isReceiveAmountEditable);
|
||||
});
|
||||
@@ -670,7 +666,6 @@ class ExchangePage extends BasePage {
|
||||
? exchangeViewModel.wallet.walletAddresses.address
|
||||
: exchangeViewModel.receiveAddress,
|
||||
initialIsAmountEditable: exchangeViewModel.isReceiveAmountEditable,
|
||||
initialIsAddressEditable: exchangeViewModel.isReceiveAddressEnabled,
|
||||
isAmountEstimated: true,
|
||||
isMoneroWallet: exchangeViewModel.isMoneroWallet,
|
||||
currencies: exchangeViewModel.receiveCurrencies,
|
||||
|
||||
@@ -174,8 +174,6 @@ class ExchangeTemplatePage extends BasePage {
|
||||
? exchangeViewModel.wallet.walletAddresses.address
|
||||
: exchangeViewModel.receiveAddress,
|
||||
initialIsAmountEditable: false,
|
||||
initialIsAddressEditable:
|
||||
exchangeViewModel.isReceiveAddressEnabled,
|
||||
isAmountEstimated: true,
|
||||
isMoneroWallet: exchangeViewModel.isMoneroWallet,
|
||||
currencies: exchangeViewModel.receiveCurrencies,
|
||||
@@ -328,11 +326,6 @@ class ExchangeTemplatePage extends BasePage {
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => exchangeViewModel.isReceiveAddressEnabled,
|
||||
(bool isEnabled) {
|
||||
receiveKey.currentState!.isAddressEditable(isEditable: isEnabled);
|
||||
});
|
||||
|
||||
reaction((_) => exchangeViewModel.provider, (ExchangeProvider? provider) {
|
||||
receiveKey.currentState!.isAmountEditable(isEditable: false);
|
||||
});
|
||||
|
||||
@@ -23,7 +23,6 @@ class ExchangeCard extends StatefulWidget {
|
||||
required this.initialAddress,
|
||||
required this.initialWalletName,
|
||||
required this.initialIsAmountEditable,
|
||||
required this.initialIsAddressEditable,
|
||||
required this.isAmountEstimated,
|
||||
required this.currencies,
|
||||
required this.onCurrencySelected,
|
||||
@@ -31,6 +30,7 @@ class ExchangeCard extends StatefulWidget {
|
||||
this.currencyValueValidator,
|
||||
this.addressTextFieldValidator,
|
||||
this.title = '',
|
||||
this.initialIsAddressEditable = true,
|
||||
this.hasRefundAddress = false,
|
||||
this.isMoneroWallet = false,
|
||||
this.currencyButtonColor = Colors.transparent,
|
||||
|
||||
@@ -43,10 +43,18 @@ class OtherSettingsPage extends BasePage {
|
||||
if(_otherSettingsViewModel.isEnabledBuyAction)
|
||||
SettingsPickerCell(
|
||||
title: S.current.default_buy_provider,
|
||||
items: _otherSettingsViewModel.availableBuyProviders,
|
||||
items: _otherSettingsViewModel.availableBuyProvidersTypes,
|
||||
displayItem: _otherSettingsViewModel.getBuyProviderType,
|
||||
selectedItem: _otherSettingsViewModel.buyProviderType,
|
||||
onItemSelected: _otherSettingsViewModel.onBuyProviderTypeSelected,
|
||||
onItemSelected: _otherSettingsViewModel.onBuyProviderTypeSelected
|
||||
),
|
||||
if(_otherSettingsViewModel.isEnabledSellAction)
|
||||
SettingsPickerCell(
|
||||
title: S.current.default_sell_provider,
|
||||
items: _otherSettingsViewModel.availableSellProvidersTypes,
|
||||
displayItem: _otherSettingsViewModel.getSellProviderType,
|
||||
selectedItem: _otherSettingsViewModel.sellProviderType,
|
||||
onItemSelected: _otherSettingsViewModel.onSellProviderTypeSelected,
|
||||
),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.settings_terms_and_conditions,
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import 'package:cake_wallet/src/widgets/alert_background.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class VulnerableSeedsPopup extends StatelessWidget {
|
||||
final List<String> affectedWalletNames;
|
||||
|
||||
const VulnerableSeedsPopup(this.affectedWalletNames, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
AlertBackground(
|
||||
child: AlertDialog(
|
||||
insetPadding: EdgeInsets.only(left: 16, right: 16, bottom: 48),
|
||||
elevation: 0.0,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(30))),
|
||||
content: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30.0),
|
||||
gradient: LinearGradient(colors: [
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.firstGradientBackgroundColor,
|
||||
Theme.of(context)
|
||||
.extension<DashboardPageTheme>()!
|
||||
.secondGradientBackgroundColor,
|
||||
], begin: Alignment.centerLeft, end: Alignment.centerRight)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: Stack(
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 16.0),
|
||||
child: Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: DefaultTextStyle(
|
||||
style: TextStyle(
|
||||
decoration: TextDecoration.none,
|
||||
fontSize: 24.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
),
|
||||
child: Text("Emergency Notice"),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 48, bottom: 16),
|
||||
child: Container(
|
||||
width: double.maxFinite,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: MediaQuery.of(context).size.height * 0.7,
|
||||
),
|
||||
child: Text(
|
||||
"Your Bitcoin wallet(s) below use a legacy seed format that is vulnerable, which MAY result in you losing money from these wallet(s) if no action is taken.\nWe recommend that you IMMEDIATELY create wallet(s) in Cake Wallet and immediately transfer the funds to these wallet(s).\nVulnerable wallet name(s):\n\n[${affectedWalletNames.join(", ")}]\n\nFor assistance, please use the in-app support or email support@cakewallet.com",
|
||||
style: TextStyle(
|
||||
decoration: TextDecoration.none,
|
||||
fontSize: 16.0,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context)
|
||||
.extension<DashboardPageTheme>()!
|
||||
.textColor,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
AlertCloseButton(bottom: 30)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,7 @@ abstract class AppStoreBase with Store {
|
||||
AuthenticationStore authenticationStore;
|
||||
|
||||
@observable
|
||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>?
|
||||
wallet;
|
||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>? wallet;
|
||||
|
||||
WalletListStore walletList;
|
||||
|
||||
@@ -36,16 +35,16 @@ abstract class AppStoreBase with Store {
|
||||
NodeListStore nodeListStore;
|
||||
|
||||
@action
|
||||
void changeCurrentWallet(
|
||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
|
||||
TransactionInfo>
|
||||
wallet) {
|
||||
Future<void> changeCurrentWallet(
|
||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet) async {
|
||||
this.wallet?.close();
|
||||
this.wallet = wallet;
|
||||
this.wallet!.setExceptionHandler(ExceptionHandler.onError);
|
||||
|
||||
if (isEVMCompatibleChain(wallet.type)) {
|
||||
getIt.get<Web3WalletService>().init();
|
||||
await getIt.get<Web3WalletService>().onDispose();
|
||||
getIt.get<Web3WalletService>().create();
|
||||
await getIt.get<Web3WalletService>().init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
||||
import 'package:cake_wallet/entities/cake_2fa_preset_options.dart';
|
||||
@@ -147,7 +148,9 @@ abstract class SettingsStoreBase with Store {
|
||||
initialShouldRequireTOTP2FAForAllSecurityAndBackupSettings,
|
||||
currentSyncMode = initialSyncMode,
|
||||
currentSyncAll = initialSyncAll,
|
||||
priority = ObservableMap<WalletType, TransactionPriority>() {
|
||||
priority = ObservableMap<WalletType, TransactionPriority>(),
|
||||
defaultBuyProviders = ObservableMap<WalletType, BuyProviderType>(),
|
||||
defaultSellProviders = ObservableMap<WalletType, BuyProviderType>() {
|
||||
//this.nodes = ObservableMap<WalletType, Node>.of(nodes);
|
||||
|
||||
if (initialMoneroTransactionPriority != null) {
|
||||
@@ -181,9 +184,25 @@ abstract class SettingsStoreBase with Store {
|
||||
initializeTrocadorProviderStates();
|
||||
|
||||
WalletType.values.forEach((walletType) {
|
||||
final key = 'defaultBuyProvider_${walletType.toString()}';
|
||||
final providerIndex = sharedPreferences.getInt(key);
|
||||
defaultBuyProviders[walletType] = providerIndex != null ? BuyProviderType.values[providerIndex] : BuyProviderType.AskEachTime;
|
||||
final key = 'buyProvider_${walletType.toString()}';
|
||||
final providerId = sharedPreferences.getString(key);
|
||||
if (providerId != null) {
|
||||
defaultBuyProviders[walletType] = BuyProviderType.values
|
||||
.firstWhere((provider) => provider.id == providerId, orElse: () => BuyProviderType.askEachTime);
|
||||
} else {
|
||||
defaultBuyProviders[walletType] = BuyProviderType.askEachTime;
|
||||
}
|
||||
});
|
||||
|
||||
WalletType.values.forEach((walletType) {
|
||||
final key = 'sellProvider_${walletType.toString()}';
|
||||
final providerId = sharedPreferences.getString(key);
|
||||
if (providerId != null) {
|
||||
defaultSellProviders[walletType] = BuyProviderType.values
|
||||
.firstWhere((provider) => provider.id == providerId, orElse: () => BuyProviderType.askEachTime);
|
||||
} else {
|
||||
defaultSellProviders[walletType] = BuyProviderType.askEachTime;
|
||||
}
|
||||
});
|
||||
|
||||
reaction(
|
||||
@@ -196,6 +215,20 @@ abstract class SettingsStoreBase with Store {
|
||||
(bool shouldShowYatPopup) =>
|
||||
sharedPreferences.setBool(PreferencesKey.shouldShowYatPopup, shouldShowYatPopup));
|
||||
|
||||
defaultBuyProviders.observe((change) {
|
||||
final String key = 'buyProvider_${change.key.toString()}';
|
||||
if (change.newValue != null) {
|
||||
sharedPreferences.setString(key, change.newValue!.id);
|
||||
}
|
||||
});
|
||||
|
||||
defaultSellProviders.observe((change) {
|
||||
final String key = 'sellProvider_${change.key.toString()}';
|
||||
if (change.newValue != null) {
|
||||
sharedPreferences.setString(key, change.newValue!.id);
|
||||
}
|
||||
});
|
||||
|
||||
priority.observe((change) {
|
||||
final String? key;
|
||||
switch (change.key) {
|
||||
@@ -251,16 +284,6 @@ abstract class SettingsStoreBase with Store {
|
||||
(bool disableSell) =>
|
||||
sharedPreferences.setBool(PreferencesKey.disableSellKey, disableSell));
|
||||
|
||||
reaction(
|
||||
(_) => defaultBuyProviders.asObservable(),
|
||||
(ObservableMap<WalletType, BuyProviderType> providers) {
|
||||
providers.forEach((walletType, provider) {
|
||||
final key = 'defaultBuyProvider_${walletType.toString()}';
|
||||
sharedPreferences.setInt(key, provider.index);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
reaction(
|
||||
(_) => walletListOrder,
|
||||
(WalletListOrderType walletListOrder) =>
|
||||
@@ -594,7 +617,10 @@ abstract class SettingsStoreBase with Store {
|
||||
ObservableMap<String, bool> trocadorProviderStates = ObservableMap<String, bool>();
|
||||
|
||||
@observable
|
||||
ObservableMap<WalletType, BuyProviderType> defaultBuyProviders = ObservableMap<WalletType, BuyProviderType>();
|
||||
ObservableMap<WalletType, BuyProviderType> defaultBuyProviders;
|
||||
|
||||
@observable
|
||||
ObservableMap<WalletType, BuyProviderType> defaultSellProviders;
|
||||
|
||||
@observable
|
||||
SortBalanceBy sortBalanceBy;
|
||||
|
||||
@@ -61,8 +61,7 @@ abstract class BuyViewModelBase with Store {
|
||||
String _url = '';
|
||||
|
||||
try {
|
||||
_url = await selectedProvider
|
||||
!.requestUrl(doubleAmount.toString(), fiatCurrency.title);
|
||||
_url = await selectedProvider!.requestUrl(doubleAmount.toString(), fiatCurrency.title);
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/core/key_service.dart';
|
||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
||||
@@ -24,13 +28,21 @@ import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:cryptography/cryptography.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_core/cake_hive.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/utils/file.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:eth_sig_util/util/utils.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
||||
|
||||
part 'dashboard_view_model.g.dart';
|
||||
|
||||
@@ -46,7 +58,8 @@ abstract class DashboardViewModelBase with Store {
|
||||
required this.settingsStore,
|
||||
required this.yatStore,
|
||||
required this.ordersStore,
|
||||
required this.anonpayTransactionsStore})
|
||||
required this.anonpayTransactionsStore,
|
||||
required this.keyService})
|
||||
: hasSellAction = false,
|
||||
hasBuyAction = false,
|
||||
hasExchangeAction = false,
|
||||
@@ -262,6 +275,8 @@ abstract class DashboardViewModelBase with Store {
|
||||
|
||||
bool get hasRescan => wallet.type == WalletType.monero || wallet.type == WalletType.haven;
|
||||
|
||||
final KeyService keyService;
|
||||
|
||||
BalanceViewModel balanceViewModel;
|
||||
|
||||
AppStore appStore;
|
||||
@@ -282,13 +297,31 @@ abstract class DashboardViewModelBase with Store {
|
||||
|
||||
Map<String, List<FilterItem>> filterItems;
|
||||
|
||||
BuyProviderType get defaultBuyProvider =>
|
||||
settingsStore.defaultBuyProviders[wallet.type] ??
|
||||
BuyProviderType.AskEachTime;
|
||||
BuyProvider? get defaultBuyProvider => BuyProviderHelper.getProviderByType(
|
||||
settingsStore.defaultBuyProviders[wallet.type] ?? BuyProviderType.askEachTime);
|
||||
|
||||
BuyProvider? get defaultSellProvider => BuyProviderHelper.getProviderByType(
|
||||
settingsStore.defaultSellProviders[wallet.type] ?? BuyProviderType.askEachTime);
|
||||
|
||||
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
|
||||
|
||||
List<BuyProviderType> get availableProviders => BuyProviderType.getAvailableProviders(wallet.type);
|
||||
List<BuyProvider> get availableBuyProviders {
|
||||
final providerTypes = BuyProviderHelper.getAvailableBuyProviderTypes(wallet.type);
|
||||
return providerTypes
|
||||
.map((type) => BuyProviderHelper.getProviderByType(type))
|
||||
.where((provider) => provider != null)
|
||||
.cast<BuyProvider>()
|
||||
.toList();
|
||||
}
|
||||
|
||||
List<BuyProvider> get availableSellProviders {
|
||||
final providerTypes = BuyProviderHelper.getAvailableSellProviderTypes(wallet.type);
|
||||
return providerTypes
|
||||
.map((type) => BuyProviderHelper.getProviderByType(type))
|
||||
.where((provider) => provider != null)
|
||||
.cast<BuyProvider>()
|
||||
.toList();
|
||||
}
|
||||
|
||||
bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup;
|
||||
|
||||
@@ -302,16 +335,15 @@ abstract class DashboardViewModelBase with Store {
|
||||
bool hasExchangeAction;
|
||||
|
||||
@computed
|
||||
bool get isEnabledBuyAction => !settingsStore.disableBuy && wallet.type != WalletType.haven;
|
||||
bool get isEnabledBuyAction =>
|
||||
!settingsStore.disableBuy && availableBuyProviders.isNotEmpty;
|
||||
|
||||
@observable
|
||||
bool hasBuyAction;
|
||||
|
||||
@computed
|
||||
bool get isEnabledSellAction =>
|
||||
!settingsStore.disableSell &&
|
||||
wallet.type != WalletType.haven &&
|
||||
wallet.type != WalletType.monero;
|
||||
!settingsStore.disableSell && availableSellProviders.isNotEmpty;
|
||||
|
||||
@observable
|
||||
bool hasSellAction;
|
||||
@@ -433,4 +465,32 @@ abstract class DashboardViewModelBase with Store {
|
||||
|
||||
@action
|
||||
void setSyncAll(bool value) => settingsStore.currentSyncAll = value;
|
||||
|
||||
Future<List<String>> checkAffectedWallets() async {
|
||||
// await load file
|
||||
final vulnerableSeedsString = await rootBundle.loadString('assets/text/cakewallet_weak_bitcoin_seeds_hashed_sorted_version1.txt');
|
||||
final vulnerableSeeds = vulnerableSeedsString.split("\n");
|
||||
|
||||
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
|
||||
|
||||
List<String> affectedWallets = [];
|
||||
for (var walletInfo in walletInfoSource.values) {
|
||||
if (walletInfo.type == WalletType.bitcoin) {
|
||||
final password = await keyService.getWalletPassword(walletName: walletInfo.name);
|
||||
final path = await pathForWallet(name: walletInfo.name, type: walletInfo.type);
|
||||
final jsonSource = await read(path: path, password: password);
|
||||
final data = json.decode(jsonSource) as Map;
|
||||
final mnemonic = data['mnemonic'] as String;
|
||||
|
||||
final hash = await Cryptography.instance.sha256().hash(utf8.encode(mnemonic));
|
||||
final seedSha = bytesToHex(hash.bytes);
|
||||
|
||||
if (vulnerableSeeds.contains(seedSha)) {
|
||||
affectedWallets.add(walletInfo.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return affectedWallets;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
receiveAddress = '',
|
||||
depositAddress = '',
|
||||
isDepositAddressEnabled = false,
|
||||
isReceiveAddressEnabled = false,
|
||||
isReceiveAmountEditable = false,
|
||||
_useTorOnly = false,
|
||||
receiveCurrencies = <CryptoCurrency>[],
|
||||
@@ -108,7 +107,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
bestRateSync = Timer.periodic(Duration(seconds: 10), (timer) => _calculateBestRate());
|
||||
|
||||
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
||||
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
|
||||
depositAmount = '';
|
||||
receiveAmount = '';
|
||||
receiveAddress = '';
|
||||
@@ -201,9 +199,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
@observable
|
||||
bool isDepositAddressEnabled;
|
||||
|
||||
@observable
|
||||
bool isReceiveAddressEnabled;
|
||||
|
||||
@observable
|
||||
bool isReceiveAmountEntered;
|
||||
|
||||
@@ -315,7 +310,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
isFixedRateMode = false;
|
||||
_onPairChange();
|
||||
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
||||
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -324,7 +318,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
isFixedRateMode = false;
|
||||
_onPairChange();
|
||||
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
||||
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -535,7 +528,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.address : '';
|
||||
receiveAddress = receiveCurrency == wallet.currency ? wallet.walletAddresses.address : '';
|
||||
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
||||
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
|
||||
isFixedRateMode = false;
|
||||
_onPairChange();
|
||||
}
|
||||
|
||||
@@ -50,8 +50,10 @@ abstract class OrderDetailsViewModelBase with Store {
|
||||
@action
|
||||
Future<void> _updateOrder() async {
|
||||
try {
|
||||
if (_provider != null) {
|
||||
final updatedOrder = await _provider!.findOrderById(order.id);
|
||||
if (_provider != null && (_provider is MoonPayBuyProvider || _provider is WyreBuyProvider)) {
|
||||
final updatedOrder = _provider is MoonPayBuyProvider
|
||||
? await (_provider as MoonPayBuyProvider).findOrderById(order.id)
|
||||
: await (_provider as WyreBuyProvider).findOrderById(order.id);
|
||||
updatedOrder.from = order.from;
|
||||
updatedOrder.to = order.to;
|
||||
updatedOrder.receiveAddress = order.receiveAddress;
|
||||
@@ -87,19 +89,26 @@ abstract class OrderDetailsViewModelBase with Store {
|
||||
value: order.provider.title)
|
||||
);
|
||||
|
||||
if (_provider?.trackUrl.isNotEmpty ?? false) {
|
||||
final buildURL = _provider!.trackUrl + '${order.transferId}';
|
||||
items.add(
|
||||
TrackTradeListItem(
|
||||
title: 'Track',
|
||||
value: buildURL,
|
||||
onTap: () {
|
||||
try {
|
||||
launch(buildURL);
|
||||
} catch (e) {}
|
||||
}
|
||||
)
|
||||
);
|
||||
if (_provider != null && (_provider is MoonPayBuyProvider || _provider is WyreBuyProvider)) {
|
||||
|
||||
final trackUrl = _provider is MoonPayBuyProvider
|
||||
? (_provider as MoonPayBuyProvider).trackUrl
|
||||
: (_provider as WyreBuyProvider).trackUrl;
|
||||
|
||||
if (trackUrl.isNotEmpty ?? false) {
|
||||
final buildURL = trackUrl + '${order.transferId}';
|
||||
items.add(
|
||||
TrackTradeListItem(
|
||||
title: 'Track',
|
||||
value: buildURL,
|
||||
onTap: () {
|
||||
try {
|
||||
launch(buildURL);
|
||||
} catch (e) {}
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
items.add(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
||||
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
@@ -59,12 +60,24 @@ abstract class OtherSettingsViewModelBase with Store {
|
||||
bool get isEnabledBuyAction =>
|
||||
!_settingsStore.disableBuy && _wallet.type != WalletType.haven;
|
||||
|
||||
List<BuyProviderType> get availableBuyProviders =>
|
||||
BuyProviderType.getAvailableProviders(walletType);
|
||||
@computed
|
||||
bool get isEnabledSellAction =>
|
||||
!_settingsStore.disableSell && _wallet.type != WalletType.haven;
|
||||
|
||||
List<BuyProviderType> get availableBuyProvidersTypes {
|
||||
return BuyProviderHelper.getAvailableBuyProviderTypes(walletType);
|
||||
}
|
||||
|
||||
List<BuyProviderType> get availableSellProvidersTypes =>
|
||||
BuyProviderHelper.getAvailableSellProviderTypes(walletType);
|
||||
|
||||
BuyProviderType get buyProviderType =>
|
||||
_settingsStore.defaultBuyProviders[walletType] ??
|
||||
BuyProviderType.AskEachTime;
|
||||
BuyProviderType.askEachTime;
|
||||
|
||||
BuyProviderType get sellProviderType =>
|
||||
_settingsStore.defaultSellProviders[walletType] ??
|
||||
BuyProviderType.askEachTime;
|
||||
|
||||
String getDisplayPriority(dynamic priority) {
|
||||
final _priority = priority as TransactionPriority;
|
||||
@@ -81,13 +94,27 @@ abstract class OtherSettingsViewModelBase with Store {
|
||||
|
||||
String getBuyProviderType(dynamic buyProviderType) {
|
||||
final _buyProviderType = buyProviderType as BuyProviderType;
|
||||
return _buyProviderType == BuyProviderType.askEachTime
|
||||
? S.current.ask_each_time
|
||||
: _buyProviderType.name;
|
||||
}
|
||||
|
||||
return _buyProviderType.toString();
|
||||
String getSellProviderType(dynamic sellProviderType) {
|
||||
final _sellProviderType = sellProviderType as BuyProviderType;
|
||||
return _sellProviderType == BuyProviderType.askEachTime
|
||||
? S.current.ask_each_time
|
||||
: _sellProviderType.name;
|
||||
}
|
||||
|
||||
void onDisplayPrioritySelected(TransactionPriority priority) =>
|
||||
_settingsStore.priority[_wallet.type] = priority;
|
||||
|
||||
void onBuyProviderTypeSelected(BuyProviderType buyProviderType) =>
|
||||
@action
|
||||
BuyProviderType onBuyProviderTypeSelected(BuyProviderType buyProviderType) =>
|
||||
_settingsStore.defaultBuyProviders[walletType] = buyProviderType;
|
||||
|
||||
@action
|
||||
BuyProviderType onSellProviderTypeSelected(
|
||||
BuyProviderType sellProviderType) =>
|
||||
_settingsStore.defaultSellProviders[walletType] = sellProviderType;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ abstract class WalletCreationVMBase with Store {
|
||||
: await process(credentials);
|
||||
walletInfo.address = wallet.walletAddresses.address;
|
||||
await _walletInfoSource.add(walletInfo);
|
||||
_appStore.changeCurrentWallet(wallet);
|
||||
await _appStore.changeCurrentWallet(wallet);
|
||||
getIt.get<BackgroundTasks>().registerSyncTask();
|
||||
_appStore.authenticationStore.allowed();
|
||||
state = ExecutedSuccessfullyState();
|
||||
|
||||
@@ -45,7 +45,7 @@ abstract class WalletListViewModelBase with Store {
|
||||
@action
|
||||
Future<void> loadWallet(WalletListItem walletItem) async {
|
||||
final wallet = await _walletLoadingService.load(walletItem.type, walletItem.name);
|
||||
_appStore.changeCurrentWallet(wallet);
|
||||
await _appStore.changeCurrentWallet(wallet);
|
||||
}
|
||||
|
||||
WalletListOrderType? get orderType => _appStore.settingsStore.walletListOrder;
|
||||
|
||||
Reference in New Issue
Block a user