mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 11:39:22 +00:00
CW-539-DFX-off-ramp-sell-provider (#1229)
* buy_provider_types refactoring * refactor MoonPay and sell option flow * dfx sell flow * add default sell provider flow * localization * Update other_settings_page.dart * [skip ci] update localization * [skip ci] providers fixes * [skip ci] ui fixes * refactor sell and buy flow * handle dfx availability by country * PR fixes
This commit is contained in:
parent
92914a8532
commit
914565eb72
49 changed files with 623 additions and 370 deletions
BIN
assets/images/moonpay_dark.png
Normal file
BIN
assets/images/moonpay_dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
BIN
assets/images/moonpay_light.png
Normal file
BIN
assets/images/moonpay_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -623,15 +623,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
tor:
|
||||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
|
||||
url: "https://github.com/cake-tech/tor.git"
|
||||
source: git
|
||||
version: "0.0.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -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';
|
||||
}
|
|
@ -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;
|
||||
final bool isTest;
|
||||
final String baseUrl;
|
||||
|
||||
Future<Uri> requestUrl(
|
||||
{required CryptoCurrency currency,
|
||||
Future<Uri> requestUrl({
|
||||
required CryptoCurrency currency,
|
||||
required String refundWalletAddress,
|
||||
required SettingsStore settingsStore}) async {
|
||||
|
||||
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 {
|
||||
|
@ -91,17 +140,21 @@ class MoonPayBuyProvider extends BuyProvider {
|
|||
String get title => 'Moon Pay';
|
||||
|
||||
@override
|
||||
BuyProviderDescription get description => BuyProviderDescription.moonPay;
|
||||
|
||||
String get currencyCode =>
|
||||
walletTypeToCryptoCurrency(walletType).title.toLowerCase();
|
||||
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(wallet.type).title.toLowerCase();
|
||||
|
||||
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();
|
||||
}
|
10
lib/di.dart
10
lib/di.dart
|
@ -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';
|
||||
|
@ -796,8 +797,12 @@ Future<void> setup({
|
|||
getIt
|
||||
.registerFactory<DFXBuyProvider>(() => DFXBuyProvider(wallet: getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory<OnRamperBuyProvider>(() => OnRamperBuyProvider(
|
||||
getIt.registerFactory<MoonPaySellProvider>(() => MoonPaySellProvider(
|
||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory<OnRamperBuyProvider>(() => OnRamperBuyProvider(
|
||||
getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
));
|
||||
|
||||
|
@ -941,7 +946,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
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
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());
|
||||
}
|
||||
},
|
||||
);
|
||||
if (DeviceInfo.instance.isMobile) {
|
||||
Navigator.of(context).pushNamed(Routes.webViewPage,
|
||||
arguments: [S.of(context).sell, uri]);
|
||||
} else {
|
||||
await launchUrl(uri);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
static Future<void> _showErrorDialog(
|
||||
BuildContext context, String title, String errorMessage) async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).sell,
|
||||
alertContent: S.of(context).unsupported_asset,
|
||||
alertTitle: title,
|
||||
alertContent: errorMessage,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
buttonAction: () => Navigator.of(context).pop(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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,47 +34,33 @@ 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),
|
||||
),
|
||||
),
|
||||
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),
|
||||
),
|
||||
image: icon,
|
||||
title: provider.toString(),
|
||||
description: isBuyAction
|
||||
? provider.buyOptionDescription
|
||||
: provider.sellOptionDescription,
|
||||
onPressed: () =>
|
||||
provider.launchProvider(context, isBuyAction),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
Spacer(),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
|
||||
child: Text(
|
||||
S.of(context).select_buy_provider_notice,
|
||||
isBuyAction
|
||||
? S.of(context).select_buy_provider_notice
|
||||
: S.of(context).select_sell_provider_notice,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,5 +1,6 @@
|
|||
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';
|
||||
|
@ -41,6 +42,7 @@ 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';
|
||||
|
||||
|
@ -295,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;
|
||||
|
||||
|
@ -315,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;
|
||||
|
|
|
@ -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,8 +89,14 @@ abstract class OrderDetailsViewModelBase with Store {
|
|||
value: order.provider.title)
|
||||
);
|
||||
|
||||
if (_provider?.trackUrl.isNotEmpty ?? false) {
|
||||
final buildURL = _provider!.trackUrl + '${order.transferId}';
|
||||
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',
|
||||
|
@ -101,6 +109,7 @@ abstract class OrderDetailsViewModelBase with Store {
|
|||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
items.add(
|
||||
StandartListItem(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -754,6 +754,8 @@
|
|||
"dfx_option_description": "ﺎﺑﻭﺭﻭﺃ ﻲﻓ ﺕﺎﻛﺮﺸﻟﺍﻭ ﺔﺋﺰﺠﺘﻟﺍ ءﻼﻤﻌﻟ .ﻲﻓﺎﺿﺇ KYC ﻥﻭﺪﺑ ﻭﺭﻮﻳ 990 ﻰﻟﺇ ﻞﺼﻳ ﺎﻣ .ﻱﺮﺴﻳﻮﺴﻟﺍ",
|
||||
"polygonscan_history": "ﻥﺎﻜﺴﻧﻮﺠﻴﻟﻮﺑ ﺦﻳﺭﺎﺗ",
|
||||
"wallet_seed_legacy": "بذرة محفظة قديمة",
|
||||
"default_sell_provider": " ﻲﺿﺍﺮﺘﻓﻻﺍ ﻊﻴﺒﻟﺍ ﺩﻭﺰﻣ",
|
||||
"select_sell_provider_notice": ".ﻖﻴﺒﻄﺘﻟﺍ ﺕﺍﺩﺍﺪﻋﺇ ﻲﻓ ﻚﺑ ﺹﺎﺨﻟﺍ ﻲﺿﺍﺮﺘﻓﻻﺍ ﻊﻴﺒﻟﺍ ﺩﻭﺰﻣ ﻦﻴﻴﻌﺗ ﻖﻳﺮﻃ ﻦﻋ ﺔﺷﺎﺸﻟﺍ ﻩﺬﻫ ﻲﻄﺨﺗ",
|
||||
"custom_drag": "مخصص (عقد وسحب)",
|
||||
"switchToEVMCompatibleWallet": " (Ethereum، Polygon) ﻯﺮﺧﺃ ﺓﺮﻣ ﺔﻟﻭﺎﺤﻤﻟﺍﻭ EVM ﻊﻣ ﺔﻘﻓﺍﻮﺘﻣ ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻰﺟﺮﻳ"
|
||||
}
|
||||
|
|
|
@ -750,6 +750,8 @@
|
|||
"dfx_option_description": "Купете крипто с EUR и CHF. До 990 € без допълнителен KYC. За клиенти на дребно и корпоративни клиенти в Европа",
|
||||
"polygonscan_history": "История на PolygonScan",
|
||||
"wallet_seed_legacy": "Наследено портфейл семе",
|
||||
"default_sell_provider": "Доставчик за продажба по подразбиране",
|
||||
"select_sell_provider_notice": "Изберете доставчик на продажба по-горе. Можете да пропуснете този екран, като зададете своя доставчик на продажба по подразбиране в настройките на приложението.",
|
||||
"custom_drag": "Персонализиране (задръжте и плъзнете)",
|
||||
"switchToEVMCompatibleWallet": "Моля, превключете към портфейл, съвместим с EVM, и опитайте отново (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -750,6 +750,8 @@
|
|||
"dfx_option_description": "Nakupujte kryptoměny za EUR a CHF. Až 990 € bez dalších KYC. Pro maloobchodní a firemní zákazníky v Evropě",
|
||||
"polygonscan_history": "Historie PolygonScan",
|
||||
"wallet_seed_legacy": "Starší semeno peněženky",
|
||||
"default_sell_provider": "Výchozí poskytovatel prodeje",
|
||||
"select_sell_provider_notice": "Výše vyberte poskytovatele prodeje. Tuto obrazovku můžete přeskočit nastavením výchozího poskytovatele prodeje v nastavení aplikace.",
|
||||
"custom_drag": "Custom (Hold and Drag)",
|
||||
"switchToEVMCompatibleWallet": "Přepněte na peněženku kompatibilní s EVM a zkuste to znovu (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -758,6 +758,8 @@
|
|||
"dfx_option_description": "Krypto mit EUR und CHF kaufen. Bis zu 990€ ohne zusätzliches KYC. Für Privat- und Firmenkunden in Europa",
|
||||
"polygonscan_history": "PolygonScan-Verlauf",
|
||||
"wallet_seed_legacy": "Legacy Wallet Seed",
|
||||
"default_sell_provider": "Standard-Verkaufsanbieter",
|
||||
"select_sell_provider_notice": "Wählen Sie oben einen Verkaufsanbieter aus. Sie können diesen Bildschirm überspringen, indem Sie in den App-Einstellungen Ihren Standard-Verkaufsanbieter festlegen.",
|
||||
"custom_drag": "Custom (Hold and Drag)",
|
||||
"switchToEVMCompatibleWallet": "Bitte wechseln Sie zu einem EVM-kompatiblen Wallet und versuchen Sie es erneut (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -759,6 +759,8 @@
|
|||
"dfx_option_description": "Buy crypto with EUR & CHF. Up to 990€ without additional KYC. For retail and corporate customers in Europe",
|
||||
"polygonscan_history": "PolygonScan history",
|
||||
"wallet_seed_legacy": "Legacy wallet seed",
|
||||
"default_sell_provider": "Default Sell Provider",
|
||||
"select_sell_provider_notice": "Select a sell provider above. You can skip this screen by setting your default sell provider in app settings.",
|
||||
"custom_drag": "Custom (Hold and Drag)",
|
||||
"switchToEVMCompatibleWallet": "Please switch to an EVM compatible wallet and try again (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -758,6 +758,8 @@
|
|||
"dfx_option_description": "Compre criptomonedas con EUR y CHF. Hasta 990€ sin KYC adicional. Para clientes minoristas y corporativos en Europa",
|
||||
"polygonscan_history": "Historial de PolygonScan",
|
||||
"wallet_seed_legacy": "Semilla de billetera heredada",
|
||||
"default_sell_provider": "Proveedor de venta predeterminado",
|
||||
"select_sell_provider_notice": "Seleccione un proveedor de venta arriba. Puede omitir esta pantalla configurando su proveedor de venta predeterminado en la configuración de la aplicación.",
|
||||
"custom_drag": "Custom (mantenía y arrastre)",
|
||||
"switchToEVMCompatibleWallet": "Cambie a una billetera compatible con EVM e inténtelo nuevamente (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -758,6 +758,8 @@
|
|||
"dfx_option_description": "Achetez des crypto-monnaies avec EUR et CHF. Jusqu'à 990€ sans KYC supplémentaire. Pour les clients particuliers et entreprises en Europe",
|
||||
"polygonscan_history": "Historique de PolygonScan",
|
||||
"wallet_seed_legacy": "Graine de portefeuille hérité",
|
||||
"default_sell_provider": "Fournisseur de vente par défaut",
|
||||
"select_sell_provider_notice": "Sélectionnez un fournisseur de vente ci-dessus. Vous pouvez ignorer cet écran en définissant votre fournisseur de vente par défaut dans les paramètres de l'application.",
|
||||
"custom_drag": "Custom (maintenir et traîner)",
|
||||
"switchToEVMCompatibleWallet": "Veuillez passer à un portefeuille compatible EVM et réessayer (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -736,6 +736,8 @@
|
|||
"dfx_option_description": "Sayi crypto tare da EUR & CHF. Har zuwa € 990 ba tare da ƙarin KYC ba. Don 'yan kasuwa da abokan ciniki na kamfanoni a Turai",
|
||||
"polygonscan_history": "PolygonScan tarihin kowane zamani",
|
||||
"wallet_seed_legacy": "Tallarin walat walat",
|
||||
"default_sell_provider": "Tsohuwar Mai Bayar Siyarwa",
|
||||
"select_sell_provider_notice": "Zaɓi mai bada siyarwa a sama. Kuna iya tsallake wannan allon ta saita mai bada siyar da ku a cikin saitunan app.",
|
||||
"custom_drag": "Al'ada (riƙe da ja)",
|
||||
"switchToEVMCompatibleWallet": "Da fatan za a canza zuwa walat ɗin EVM mai jituwa kuma a sake gwadawa (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -758,6 +758,8 @@
|
|||
"dfx_option_description": "EUR और CHF के साथ क्रिप्टो खरीदें। अतिरिक्त केवाईसी के बिना 990€ तक। यूरोप में खुदरा और कॉर्पोरेट ग्राहकों के लिए",
|
||||
"polygonscan_history": "पॉलीगॉनस्कैन इतिहास",
|
||||
"wallet_seed_legacy": "विरासत बटुए बीज",
|
||||
"default_sell_provider": "डिफ़ॉल्ट विक्रय प्रदाता",
|
||||
"select_sell_provider_notice": "ऊपर एक विक्रय प्रदाता का चयन करें। आप ऐप सेटिंग में अपना डिफ़ॉल्ट विक्रय प्रदाता सेट करके इस स्क्रीन को छोड़ सकते हैं।",
|
||||
"custom_drag": "कस्टम (पकड़ और खींचें)",
|
||||
"switchToEVMCompatibleWallet": "कृपया ईवीएम संगत वॉलेट पर स्विच करें और पुनः प्रयास करें (एथेरियम, पॉलीगॉन)"
|
||||
}
|
||||
|
|
|
@ -756,6 +756,8 @@
|
|||
"dfx_option_description": "Kupujte kripto s EUR i CHF. Do 990 € bez dodatnog KYC-a. Za maloprodajne i poslovne korisnike u Europi",
|
||||
"polygonscan_history": "Povijest PolygonScan",
|
||||
"wallet_seed_legacy": "Sjeme naslijeđenog novčanika",
|
||||
"default_sell_provider": "Zadani dobavljač prodaje",
|
||||
"select_sell_provider_notice": "Gore odaberite pružatelja usluga prodaje. Ovaj zaslon možete preskočiti postavljanjem zadanog pružatelja usluga prodaje u postavkama aplikacije.",
|
||||
"custom_drag": "Prilagođeni (držite i povucite)",
|
||||
"switchToEVMCompatibleWallet": "Prijeđite na novčanik kompatibilan s EVM-om i pokušajte ponovno (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -746,6 +746,8 @@
|
|||
"dfx_option_description": "Beli kripto dengan EUR & CHF. Hingga 990€ tanpa KYC tambahan. Untuk pelanggan ritel dan korporat di Eropa",
|
||||
"polygonscan_history": "Sejarah PolygonScan",
|
||||
"wallet_seed_legacy": "Biji dompet warisan",
|
||||
"default_sell_provider": "Penyedia Penjualan Default",
|
||||
"select_sell_provider_notice": "Pilih penyedia jual di atas. Anda dapat melewati layar ini dengan mengatur penyedia penjualan default Anda di pengaturan aplikasi.",
|
||||
"custom_drag": "Khusus (tahan dan seret)",
|
||||
"switchToEVMCompatibleWallet": "Silakan beralih ke dompet yang kompatibel dengan EVM dan coba lagi (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -758,6 +758,8 @@
|
|||
"dfx_option_description": "Acquista criptovalute con EUR e CHF. Fino a 990€ senza KYC aggiuntivi. Per clienti al dettaglio e aziendali in Europa",
|
||||
"polygonscan_history": "Cronologia PolygonScan",
|
||||
"wallet_seed_legacy": "Seme di portafoglio legacy",
|
||||
"default_sell_provider": "Fornitore di vendita predefinito",
|
||||
"select_sell_provider_notice": "Seleziona un fornitore di vendita sopra. Puoi saltare questa schermata impostando il tuo fornitore di vendita predefinito nelle impostazioni dell'app.",
|
||||
"custom_drag": "Custom (Hold and Drag)",
|
||||
"switchToEVMCompatibleWallet": "Passa a un portafoglio compatibile con EVM e riprova (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -758,6 +758,8 @@
|
|||
"dfx_option_description": "EUR と CHF で暗号通貨を購入します。追加のKYCなしで最大990ユーロ。ヨーロッパの小売および法人顧客向け",
|
||||
"polygonscan_history": "ポリゴンスキャン履歴",
|
||||
"wallet_seed_legacy": "レガシーウォレットシード",
|
||||
"default_sell_provider": "デフォルトの販売プロバイダー",
|
||||
"select_sell_provider_notice": "上記の販売プロバイダーを選択してください。アプリ設定でデフォルトの販売プロバイダーを設定することで、この画面をスキップできます。",
|
||||
"custom_drag": "カスタム(ホールドとドラッグ)",
|
||||
"switchToEVMCompatibleWallet": "EVM 互換のウォレットに切り替えて再試行してください (イーサリアム、ポリゴン)"
|
||||
}
|
||||
|
|
|
@ -756,6 +756,8 @@
|
|||
"dfx_option_description": "EUR 및 CHF로 암호화폐를 구매하세요. 추가 KYC 없이 최대 990€. 유럽의 소매 및 기업 고객용",
|
||||
"polygonscan_history": "다각형 스캔 기록",
|
||||
"wallet_seed_legacy": "레거시 지갑 시드",
|
||||
"default_sell_provider": "기본 판매 공급자",
|
||||
"select_sell_provider_notice": "위에서 판매 공급자를 선택하세요. 앱 설정에서 기본 판매 공급자를 설정하면 이 화면을 건너뛸 수 있습니다.",
|
||||
"custom_drag": "사용자 정의 (홀드 앤 드래그)",
|
||||
"switchToEVMCompatibleWallet": "EVM 호환 지갑으로 전환 후 다시 시도해 주세요. (이더리움, 폴리곤)"
|
||||
}
|
||||
|
|
|
@ -756,6 +756,8 @@
|
|||
"dfx_option_description": "EUR & CHF ဖြင့် crypto ကိုဝယ်ပါ။ အပို KYC မပါဘဲ 990€ အထိ။ ဥရောပရှိ လက်လီရောင်းချသူများနှင့် ကော်ပိုရိတ်ဖောက်သည်များအတွက်",
|
||||
"polygonscan_history": "PolygonScan မှတ်တမ်း",
|
||||
"wallet_seed_legacy": "အမွေအနှစ်ပိုက်ဆံအိတ်မျိုးစေ့",
|
||||
"default_sell_provider": "ပုံသေရောင်းချပေးသူ",
|
||||
"select_sell_provider_notice": "အထက်ဖော်ပြပါ အရောင်းဝန်ဆောင်မှုပေးသူကို ရွေးပါ။ အက်ပ်ဆက်တင်များတွင် သင်၏မူလရောင်းချပေးသူကို သတ်မှတ်ခြင်းဖြင့် ဤစခရင်ကို ကျော်နိုင်သည်။",
|
||||
"custom_drag": "စိတ်ကြိုက် (Drag)",
|
||||
"switchToEVMCompatibleWallet": "ကျေးဇူးပြု၍ EVM တွဲဖက်သုံးနိုင်သော ပိုက်ဆံအိတ်သို့ ပြောင်းပြီး ထပ်စမ်းကြည့်ပါ (Ethereum၊ Polygon)"
|
||||
}
|
||||
|
|
|
@ -758,6 +758,8 @@
|
|||
"dfx_option_description": "Koop crypto met EUR & CHF. Tot 990€ zonder extra KYC. Voor particuliere en zakelijke klanten in Europa",
|
||||
"polygonscan_history": "PolygonScan-geschiedenis",
|
||||
"wallet_seed_legacy": "Legacy portemonnee zaad",
|
||||
"default_sell_provider": "Standaard verkoopaanbieder",
|
||||
"select_sell_provider_notice": "Selecteer hierboven een verkoopaanbieder. U kunt dit scherm overslaan door uw standaardverkoopprovider in te stellen in de app-instellingen.",
|
||||
"custom_drag": "Custom (vasthouden en slepen)",
|
||||
"switchToEVMCompatibleWallet": "Schakel over naar een EVM-compatibele portemonnee en probeer het opnieuw (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -758,6 +758,8 @@
|
|||
"dfx_option_description": "Kupuj kryptowaluty za EUR i CHF. Do 990 € bez dodatkowego KYC. Dla klientów detalicznych i korporacyjnych w Europie",
|
||||
"polygonscan_history": "Historia PolygonScan",
|
||||
"wallet_seed_legacy": "Dziedziczne ziarno portfela",
|
||||
"default_sell_provider": "Domyślny dostawca sprzedaży",
|
||||
"select_sell_provider_notice": "Wybierz dostawcę sprzedaży powyżej. Możesz pominąć ten ekran, ustawiając domyślnego dostawcę sprzedaży w ustawieniach aplikacji.",
|
||||
"custom_drag": "Niestandardowe (trzymaj i przeciągnij)",
|
||||
"switchToEVMCompatibleWallet": "Przejdź na portfel zgodny z EVM i spróbuj ponownie (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -757,6 +757,8 @@
|
|||
"dfx_option_description": "Compre criptografia com EUR e CHF. Até 990€ sem KYC adicional. Para clientes de varejo e corporativos na Europa",
|
||||
"polygonscan_history": "História do PolygonScan",
|
||||
"wallet_seed_legacy": "Semente de carteira herdada",
|
||||
"default_sell_provider": "Provedor de venda padrão",
|
||||
"select_sell_provider_notice": "Selecione um fornecedor de venda acima. Você pode pular esta tela definindo seu provedor de venda padrão nas configurações do aplicativo.",
|
||||
"custom_drag": "Personalizado (segure e arraste)",
|
||||
"switchToEVMCompatibleWallet": "Mude para uma carteira compatível com EVM e tente novamente (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -758,6 +758,8 @@
|
|||
"dfx_option_description": "Покупайте криптовалюту за EUR и CHF. До 990€ без дополнительного KYC. Для розничных и корпоративных клиентов в Европе",
|
||||
"polygonscan_history": "История PolygonScan",
|
||||
"wallet_seed_legacy": "Наследие семя кошелька",
|
||||
"default_sell_provider": "Поставщик продаж по умолчанию",
|
||||
"select_sell_provider_notice": "Выберите поставщика услуг продажи выше. Вы можете пропустить этот экран, установив поставщика услуг продаж по умолчанию в настройках приложения.",
|
||||
"custom_drag": "Пользователь (удерживайте и перетаскивайте)",
|
||||
"switchToEVMCompatibleWallet": "Пожалуйста, переключитесь на кошелек, совместимый с EVM, и повторите попытку (Ethereum, Polygon)."
|
||||
}
|
||||
|
|
|
@ -756,6 +756,8 @@
|
|||
"dfx_option_description": "ซื้อ crypto ด้วย EUR และ CHF สูงถึง 990€ โดยไม่มี KYC เพิ่มเติม สำหรับลูกค้ารายย่อยและลูกค้าองค์กรในยุโรป",
|
||||
"polygonscan_history": "ประวัติ PolygonScan",
|
||||
"wallet_seed_legacy": "เมล็ดกระเป๋าเงินมรดก",
|
||||
"default_sell_provider": "ผู้ให้บริการการขายเริ่มต้น",
|
||||
"select_sell_provider_notice": "เลือกผู้ให้บริการการขายด้านบน คุณสามารถข้ามหน้าจอนี้ได้โดยการตั้งค่าผู้ให้บริการการขายเริ่มต้นในการตั้งค่าแอป",
|
||||
"custom_drag": "กำหนดเอง (ค้างและลาก)",
|
||||
"switchToEVMCompatibleWallet": "โปรดเปลี่ยนไปใช้กระเป๋าเงินที่รองรับ EVM แล้วลองอีกครั้ง (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -752,6 +752,8 @@
|
|||
"dfx_option_description": "Bumili ng crypto gamit ang EUR at CHF. Hanggang 990€ nang walang karagdagang KYC. Para sa retail at corporate na mga customer sa Europe",
|
||||
"polygonscan_history": "Kasaysayan ng PolygonScan",
|
||||
"wallet_seed_legacy": "Legacy wallet seed",
|
||||
"default_sell_provider": "Default na Sell Provider",
|
||||
"select_sell_provider_notice": "Pumili ng provider ng nagbebenta sa itaas. Maaari mong laktawan ang screen na ito sa pamamagitan ng pagtatakda ng iyong default na sell provider sa mga setting ng app.",
|
||||
"custom_drag": "Pasadyang (hawakan at i -drag)",
|
||||
"switchToEVMCompatibleWallet": "Mangyaring lumipat sa isang EVM compatible na wallet at subukang muli (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -756,6 +756,8 @@
|
|||
"dfx_option_description": "EUR ve CHF ile kripto satın alın. Ek KYC olmadan 990 €'ya kadar. Avrupa'daki perakende ve kurumsal müşteriler için",
|
||||
"polygonscan_history": "PolygonScan geçmişi",
|
||||
"wallet_seed_legacy": "Eski cüzdan tohumu",
|
||||
"default_sell_provider": "Varsayılan Satış Sağlayıcısı",
|
||||
"select_sell_provider_notice": "Yukarıdan bir satış sağlayıcısı seçin. Uygulama ayarlarında varsayılan satış sağlayıcınızı ayarlayarak bu ekranı atlayabilirsiniz.",
|
||||
"custom_drag": "Özel (Bekle ve Sürükle)",
|
||||
"switchToEVMCompatibleWallet": "Lütfen EVM uyumlu bir cüzdana geçin ve tekrar deneyin (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -758,6 +758,8 @@
|
|||
"seed_language_chinese_traditional": "Китайський (традиційний)",
|
||||
"polygonscan_history": "Історія PolygonScan",
|
||||
"wallet_seed_legacy": "Спадець насіння гаманця",
|
||||
"default_sell_provider": "Постачальник продажу за замовчуванням",
|
||||
"select_sell_provider_notice": "Виберіть вище постачальника послуг продажу. Ви можете пропустити цей екран, встановивши постачальника послуг продажу за умовчанням у налаштуваннях програми.",
|
||||
"custom_drag": "На замовлення (утримуйте та перетягується)",
|
||||
"switchToEVMCompatibleWallet": "Перейдіть на гаманець, сумісний з EVM, і повторіть спробу (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -750,6 +750,8 @@
|
|||
"dfx_option_description": "EUR ﺭﻭﺍ CHF ﯽﻓﺎﺿﺍ ۔ﮟﯾﺪﯾﺮﺧ ﻮﭩﭘﺮﮐ ﮫﺗﺎﺳ ﮯﮐ KYC ﮯﯿﻟ ﮯﮐ ﻦﯿﻓﺭﺎﺻ ﭧﯾﺭﻮﭘﺭﺎﮐ ﺭﻭﺍ ﮦﺩﺭﻮﺧ ﮟ",
|
||||
"polygonscan_history": "ﺦﯾﺭﺎﺗ ﯽﮐ ﻦﯿﮑﺳﺍ ﻥﻮﮔ ﯽﻟﻮﭘ",
|
||||
"wallet_seed_legacy": "میراثی پرس کا بیج",
|
||||
"default_sell_provider": " ﮦﺪﻨﻨﮐ ﻢﮨﺍﺮﻓ ﻞﯿﺳ ﭧﻟﺎﻔﯾﮈ",
|
||||
"select_sell_provider_notice": "۔ﮟﯿﮨ ﮯﺘﮑﺳ ﮌﻮﮭﭼ ﻮﮐ ﻦﯾﺮﮑﺳﺍ ﺱﺍ ﺮﮐ ﮮﺩ ﺐﯿﺗﺮﺗ ﻮﮐ ﮦﺪﻨﻨﮐ ﻢﮨﺍﺮﻓ ﻞﯿﺳ ﭧﻟﺎﻔﯾﮈ ﮯﻨﭘﺍ ﮟﯿﻣ ﺕﺎﺒ",
|
||||
"custom_drag": "کسٹم (ہولڈ اینڈ ڈریگ)",
|
||||
"switchToEVMCompatibleWallet": "(Ethereum, Polygon) ﮟﯾﺮﮐ ﺶﺷﻮﮐ ﮦﺭﺎﺑﻭﺩ ﺭﻭﺍ ﮟﯾﺮﮐ ﭻﺋﻮﺳ ﺮﭘ ﭧﯿﻟﺍﻭ ﮯﻟﺍﻭ ﮯﻨﮭﮐﺭ ﺖﻘﺑﺎﻄﻣ "
|
||||
}
|
||||
|
|
|
@ -752,6 +752,8 @@
|
|||
"dfx_option_description": "Ra crypto pẹlu EUR & CHF. Titi di 990 € laisi afikun KYC. Fun soobu ati awọn onibara ile-iṣẹ ni Yuroopu",
|
||||
"polygonscan_history": "PolygonScan itan",
|
||||
"wallet_seed_legacy": "Irugbin akole",
|
||||
"default_sell_provider": "Aiyipada Olupese Tita",
|
||||
"select_sell_provider_notice": "Yan olupese ti o ta loke. O le foju iboju yii nipa tito olupese iṣẹ tita aiyipada rẹ ni awọn eto app.",
|
||||
"custom_drag": "Aṣa (mu ati fa)",
|
||||
"switchToEVMCompatibleWallet": "Jọwọ yipada si apamọwọ ibaramu EVM ki o tun gbiyanju lẹẹkansi (Ethereum, Polygon)"
|
||||
}
|
||||
|
|
|
@ -757,6 +757,8 @@
|
|||
"dfx_option_description": "用欧元和瑞士法郎购买加密货币。高达 990 欧元,无需额外 KYC。对于欧洲的零售和企业客户",
|
||||
"polygonscan_history": "多边形扫描历史",
|
||||
"wallet_seed_legacy": "旧的钱包种子",
|
||||
"default_sell_provider": "默认销售提供商",
|
||||
"select_sell_provider_notice": "选择上面的销售提供商。您可以通过在应用程序设置中设置默认销售提供商来跳过此屏幕。",
|
||||
"custom_drag": "定制(保持和拖动)",
|
||||
"switchToEVMCompatibleWallet": "请切换到 EVM 兼容钱包并重试(以太坊、Polygon)"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue