Merge branch 'main' into CW-529-Modify-2FA-introduction-screens

This commit is contained in:
Serhii
2023-12-13 14:44:38 +02:00
192 changed files with 4245 additions and 1139 deletions
+179
View File
@@ -0,0 +1,179 @@
import 'dart:convert';
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:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart';
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;
static const _baseUrl = 'api.dfx.swiss';
static const _authPath = '/v1/auth/signMessage';
static const _signUpPath = '/v1/auth/signUp';
static const _signInPath = '/v1/auth/signIn';
static const walletName = 'CakeWallet';
String get assetOut {
switch (_wallet.type) {
case WalletType.bitcoin:
return 'BTC';
case WalletType.bitcoinCash:
return 'BCH';
case WalletType.litecoin:
return 'LTC';
case WalletType.monero:
return 'XMR';
case WalletType.ethereum:
return 'ETH';
default:
throw Exception("WalletType is not available for DFX ${_wallet.type}");
}
}
String get blockchain {
switch (_wallet.type) {
case WalletType.bitcoin:
case WalletType.bitcoinCash:
case WalletType.litecoin:
return 'Bitcoin';
case WalletType.monero:
return 'Monero';
case WalletType.ethereum:
return 'Ethereum';
default:
throw Exception("WalletType is not available for DFX ${_wallet.type}");
}
}
Future<String> getSignMessage() async {
final walletAddress = _wallet.walletAddresses.address;
final uri = Uri.https(_baseUrl, _authPath, {'address': walletAddress});
var response = await http.get(uri, headers: {'accept': 'application/json'});
if (response.statusCode == 200) {
final responseBody = jsonDecode(response.body);
return responseBody['message'] as String;
} else {
throw Exception(
'Failed to get sign message. Status: ${response.statusCode} ${response.body}');
}
}
Future<String> signUp() async {
final signMessage = getSignature(await getSignMessage());
final walletAddress = _wallet.walletAddresses.address;
final requestBody = jsonEncode({
'wallet': walletName,
'address': walletAddress,
'signature': signMessage,
});
final uri = Uri.https(_baseUrl, _signUpPath);
var response = await http.post(uri,
headers: {'Content-Type': 'application/json'}, body: requestBody);
if (response.statusCode == 201) {
final responseBody = jsonDecode(response.body);
return responseBody['accessToken'] as String;
} else {
throw Exception(
'Failed to sign up. Status: ${response.statusCode} ${response.body}');
}
}
Future<String> signIn() async {
final signMessage = getSignature(await getSignMessage());
final walletAddress = _wallet.walletAddresses.address;
final requestBody = jsonEncode({
'address': walletAddress,
'signature': signMessage,
});
final uri = Uri.https(_baseUrl, _signInPath);
var response = await http.post(uri,
headers: {'Content-Type': 'application/json'}, body: requestBody);
if (response.statusCode == 201) {
final responseBody = jsonDecode(response.body);
return responseBody['accessToken'] as String;
} else {
throw Exception(
'Failed to sign in. Status: ${response.statusCode} ${response.body}');
}
}
String getSignature(String message) {
switch (_wallet.type) {
case WalletType.ethereum:
return _wallet.signMessage(message);
case WalletType.monero:
case WalletType.litecoin:
case WalletType.bitcoin:
case WalletType.bitcoinCash:
return _wallet.signMessage(message,
address: _wallet.walletAddresses.address);
default:
throw Exception("WalletType is not available for DFX ${_wallet.type}");
}
}
Future<void> launchProvider(BuildContext context) async {
try {
final assetOut = this.assetOut;
final blockchain = this.blockchain;
String accessToken;
try {
accessToken = await signUp();
} on Exception catch (e) {
if (e.toString().contains('409')) {
accessToken = await signIn();
} else {
rethrow;
}
}
final uri = Uri.https('services.dfx.swiss', '/buy', {
'session': accessToken,
'lang': 'en',
'asset-out': assetOut,
'blockchain': blockchain,
'asset-in': 'EUR',
});
if (await canLaunchUrl(uri)) {
if (DeviceInfo.instance.isMobile) {
Navigator.of(context).pushNamed(Routes.webViewPage,
arguments: [S.of(context).buy, uri]);
} else {
await launchUrl(uri, mode: LaunchMode.externalApplication);
}
} else {
throw Exception('Could not launch URL');
}
} catch (e) {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: "DFX Connect",
alertContent: S.of(context).buy_provider_unavailable + ': $e',
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
}
}
}
+2
View File
@@ -271,6 +271,8 @@ class AddressValidator extends TextValidator {
'|([^0-9a-zA-Z]|^)ltc[a-zA-Z0-9]{26,45}([^0-9a-zA-Z]|\$)';
case CryptoCurrency.eth:
return '0x[0-9a-zA-Z]{42}';
case CryptoCurrency.maticpoly:
return '0x[0-9a-zA-Z]{42}';
case CryptoCurrency.nano:
return 'nano_[0-9a-zA-Z]{60}';
case CryptoCurrency.banano:
+4
View File
@@ -436,6 +436,7 @@ class BackupService {
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
final backupPassword = keychainJSON[backupPasswordKey] as String;
await _flutterSecureStorage.delete(key: backupPasswordKey);
await _flutterSecureStorage.write(key: backupPasswordKey, value: backupPassword);
keychainWalletsInfo.forEach((dynamic rawInfo) async {
@@ -443,6 +444,7 @@ class BackupService {
await importWalletKeychainInfo(info);
});
await _flutterSecureStorage.delete(key: pinCodeKey);
await _flutterSecureStorage.write(key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
keychainDumpFile.deleteSync();
@@ -462,6 +464,7 @@ class BackupService {
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
final backupPassword = keychainJSON[backupPasswordKey] as String;
await _flutterSecureStorage.delete(key: backupPasswordKey);
await _flutterSecureStorage.write(key: backupPasswordKey, value: backupPassword);
keychainWalletsInfo.forEach((dynamic rawInfo) async {
@@ -469,6 +472,7 @@ class BackupService {
await importWalletKeychainInfo(info);
});
await _flutterSecureStorage.delete(key: pinCodeKey);
await _flutterSecureStorage.write(key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
keychainDumpFile.deleteSync();
+1 -1
View File
@@ -16,7 +16,7 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
final Map<String, String> queryParams = {
'interval_count': '1',
'base': crypto,
'base': crypto.split(".").first,
'quote': fiat,
'key': secrets.fiatApiKey,
};
+1
View File
@@ -19,6 +19,7 @@ class KeyService {
key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
final encodedPassword = encodeWalletPassword(password: password);
await _secureStorage.delete(key: key);
await _secureStorage.write(key: key, value: encodedPassword);
}
+3
View File
@@ -3,6 +3,7 @@ import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/haven/haven.dart';
import 'package:cake_wallet/core/validator.dart';
import 'package:cake_wallet/entities/mnemonic_item.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/nano/nano.dart';
@@ -34,6 +35,8 @@ class SeedValidator extends Validator<MnemonicItem> {
case WalletType.nano:
case WalletType.banano:
return nano!.getNanoWordList(language);
case WalletType.polygon:
return polygon!.getPolygonWordList(language);
default:
return [];
}
+18 -10
View File
@@ -6,6 +6,7 @@ import 'package:cake_wallet/core/wallet_connect/eth_transaction_model.dart';
import 'package:cake_wallet/core/wallet_connect/evm_chain_id.dart';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
@@ -14,7 +15,6 @@ import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_widget
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart';
import 'package:cake_wallet/src/screens/wallet_connect/utils/string_parsing.dart';
import 'package:convert/convert.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:eth_sig_util/eth_sig_util.dart';
import 'package:eth_sig_util/util/utils.dart';
import 'package:http/http.dart' as http;
@@ -46,13 +46,12 @@ class EvmChainServiceImpl implements ChainService {
required this.wcKeyService,
required this.bottomSheetService,
required this.wallet,
Web3Client? ethClient,
}) : ethClient = ethClient ??
Web3Client? web3Client,
}) : ethClient = web3Client ??
Web3Client(
appStore.settingsStore.getCurrentNode(WalletType.ethereum).uri.toString(),
appStore.settingsStore.getCurrentNode(appStore.wallet!.type).uri.toString(),
http.Client(),
) {
for (final String event in getEvents()) {
wallet.registerEventEmitter(chainId: getChainId(), event: event);
}
@@ -138,7 +137,8 @@ class EvmChainServiceImpl implements ChainService {
try {
// Load the private key
final List<ChainKeyModel> keys = wcKeyService.getKeysForChain(getChainId());
final List<ChainKeyModel> keys = wcKeyService
.getKeysForChain(getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type));
final Credentials credentials = EthPrivateKey.fromHex(keys[0].privateKey);
@@ -176,13 +176,15 @@ class EvmChainServiceImpl implements ChainService {
try {
// Load the private key
final List<ChainKeyModel> keys = wcKeyService.getKeysForChain(getChainId());
final List<ChainKeyModel> keys = wcKeyService
.getKeysForChain(getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type));
final EthPrivateKey credentials = EthPrivateKey.fromHex(keys[0].privateKey);
final String signature = hex.encode(
credentials.signPersonalMessageToUint8List(
Uint8List.fromList(utf8.encode(message)),
chainId: getChainIdBasedOnWalletType(appStore.wallet!.type),
),
);
log(signature);
@@ -212,7 +214,8 @@ class EvmChainServiceImpl implements ChainService {
}
// Load the private key
final List<ChainKeyModel> keys = wcKeyService.getKeysForChain(getChainId());
final List<ChainKeyModel> keys = wcKeyService
.getKeysForChain(getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type));
final Credentials credentials = EthPrivateKey.fromHex(keys[0].privateKey);
@@ -232,7 +235,11 @@ class EvmChainServiceImpl implements ChainService {
);
try {
final result = await ethClient.sendTransaction(credentials, transaction);
final result = await ethClient.sendTransaction(
credentials,
transaction,
chainId: getChainIdBasedOnWalletType(appStore.wallet!.type),
);
log('Result: $result');
@@ -267,7 +274,8 @@ class EvmChainServiceImpl implements ChainService {
return authError;
}
final List<ChainKeyModel> keys = wcKeyService.getKeysForChain(getChainId());
final List<ChainKeyModel> keys = wcKeyService
.getKeysForChain(getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type));
return EthSigUtil.signTypedData(
privateKey: keys[0].privateKey,
@@ -1,9 +1,11 @@
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:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart';
abstract class WalletConnectKeyService {
/// Returns a list of all the keys.
@@ -32,16 +34,36 @@ class KeyServiceImpl implements WalletConnectKeyService {
'eip155:42161',
'eip155:80001',
],
privateKey: ethereum!.getPrivateKey(wallet),
publicKey: ethereum!.getPublicKey(wallet),
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:
return ethereum!.getPrivateKey(wallet);
case WalletType.polygon:
return polygon!.getPrivateKey(wallet);
default:
return '';
}
}
static String _getPublicKeyForWallet(WalletBase wallet) {
switch (wallet.type) {
case WalletType.ethereum:
return ethereum!.getPublicKey(wallet);
case WalletType.polygon:
return polygon!.getPublicKey(wallet);
default:
return '';
}
}
@override
List<String> getChains() {
final List<String> chainIds = [];
@@ -9,6 +9,7 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/wallet_connect/models/auth_request_model.dart';
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
import 'package:cake_wallet/core/wallet_connect/models/session_request_model.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_request_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart';
@@ -164,8 +165,10 @@ abstract class Web3WalletServiceBase with Store {
void _onSessionProposal(SessionProposalEvent? args) async {
if (args != null) {
final chaindIdNamespace = getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type);
final Widget modalWidget = Web3RequestModal(
child: ConnectionRequestWidget(
chaindIdNamespace: chaindIdNamespace,
wallet: _web3Wallet,
sessionProposal: SessionRequestModel(request: args.params),
),
@@ -232,12 +235,13 @@ abstract class Web3WalletServiceBase with Store {
@action
Future<void> _onAuthRequest(AuthRequest? args) async {
if (args != null) {
List<ChainKeyModel> chainKeys = walletKeyService.getKeysForChain('eip155:1');
final chaindIdNamespace = getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type);
List<ChainKeyModel> chainKeys = walletKeyService.getKeysForChain(chaindIdNamespace);
// Create the message to be signed
final String iss = 'did:pkh:eip155:1:${chainKeys.first.publicKey}';
final String iss = 'did:pkh:$chaindIdNamespace:${chainKeys.first.publicKey}';
final Widget modalWidget = Web3RequestModal(
child: ConnectionRequestWidget(
chaindIdNamespace: chaindIdNamespace,
wallet: _web3Wallet,
authRequest: AuthRequestModel(iss: iss, request: args),
),
+16 -5
View File
@@ -18,6 +18,8 @@ import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/ionia/ionia_anypay.dart';
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
import 'package:cake_wallet/ionia/ionia_tip.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
import 'package:cake_wallet/src/screens/buy/buy_options_page.dart';
@@ -88,6 +90,7 @@ import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dar
import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_create_view_model.dart';
import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
@@ -225,6 +228,7 @@ import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/entities/qr_view_data.dart';
import 'buy/dfx/dfx_buy_provider.dart';
import 'core/totp_request_details.dart';
import 'src/screens/settings/desktop_settings/desktop_settings_page.dart';
@@ -720,6 +724,8 @@ Future<void> setup({
getIt.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!));
getIt.registerFactory<SeedTypeViewModel>(() => SeedTypeViewModel(getIt.get<AppStore>()));
getIt.registerFactoryParam<WalletSeedPage, bool, void>((bool isWalletCreated, _) =>
WalletSeedPage(getIt.get<WalletSeedViewModel>(), isNewWalletCreated: isWalletCreated));
@@ -754,7 +760,7 @@ Future<void> setup({
final wallet = getIt.get<AppStore>().wallet;
return ConnectionSyncPage(
getIt.get<DashboardViewModel>(),
wallet?.type == WalletType.ethereum ? getIt.get<Web3WalletService>() : null,
isEVMCompatibleChain(wallet!.type) ? getIt.get<Web3WalletService>() : null,
);
});
@@ -797,6 +803,9 @@ Future<void> setup({
getIt.registerFactory<RobinhoodBuyProvider>(
() => RobinhoodBuyProvider(wallet: getIt.get<AppStore>().wallet!));
getIt.registerFactory<DFXBuyProvider>(
() => DFXBuyProvider(wallet: getIt.get<AppStore>().wallet!));
getIt.registerFactory<OnRamperBuyProvider>(() => OnRamperBuyProvider(
settingsStore: getIt.get<AppStore>().settingsStore,
wallet: getIt.get<AppStore>().wallet!,
@@ -848,9 +857,11 @@ Future<void> setup({
return ethereum!.createEthereumWalletService(_walletInfoSource);
case WalletType.bitcoinCash:
return bitcoinCash!
.createBitcoinCashWalletService(_walletInfoSource, _unspentCoinsInfoSource!);
.createBitcoinCashWalletService(_walletInfoSource, _unspentCoinsInfoSource);
case WalletType.nano:
return nano!.createNanoWalletService(_walletInfoSource);
case WalletType.polygon:
return polygon!.createPolygonWalletService(_walletInfoSource);
default:
throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService');
}
@@ -875,8 +886,8 @@ Future<void> setup({
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
type: type));
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>(
(type, _) => WalletRestorePage(getIt.get<WalletRestoreViewModel>(param1: type)));
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>((type, _) => WalletRestorePage(
getIt.get<WalletRestoreViewModel>(param1: type), getIt.get<SeedTypeViewModel>()));
getIt.registerFactoryParam<WalletRestoreChooseDerivationViewModel, List<DerivationInfo>, void>(
(derivations, _) => WalletRestoreChooseDerivationViewModel(derivationInfos: derivations));
@@ -940,7 +951,7 @@ Future<void> setup({
getIt.registerFactory(() => BuyAmountViewModel());
getIt.registerFactory(() => BuyOptionsPage());
getIt.registerFactory(() => BuyOptionsPage(getIt.get<DashboardViewModel>()));
getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet;
+39 -1
View File
@@ -1,9 +1,11 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cw_core/wallet_type.dart';
enum BuyProviderType {
AskEachTime,
Robinhood,
Onramper;
Onramper,
DFX;
@override
String toString() {
@@ -14,6 +16,42 @@ enum BuyProviderType {
return "Robinhood";
case BuyProviderType.Onramper:
return "Onramper";
case BuyProviderType.DFX:
return "DFX";
}
}
static List<BuyProviderType> getAvailableProviders(WalletType walletType) {
switch (walletType) {
case WalletType.nano:
case WalletType.banano:
return [
BuyProviderType.AskEachTime,
BuyProviderType.Onramper
];
case WalletType.monero:
return [
BuyProviderType.AskEachTime,
BuyProviderType.Onramper,
BuyProviderType.DFX
];
case WalletType.bitcoin:
case WalletType.ethereum:
return [
BuyProviderType.AskEachTime,
BuyProviderType.Onramper,
BuyProviderType.DFX,
BuyProviderType.Robinhood
];
case WalletType.litecoin:
case WalletType.bitcoinCash:
return [
BuyProviderType.AskEachTime,
BuyProviderType.Onramper,
BuyProviderType.Robinhood
];
default:
return [];
}
}
}
+103 -35
View File
@@ -1,5 +1,6 @@
import 'dart:io' show Directory, File, Platform;
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/entities/encrypt.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cake_wallet/entities/secret_store_key.dart';
@@ -26,6 +27,7 @@ const cakeWalletBitcoinElectrumUri = 'electrum.cakewallet.com:50002';
const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002';
const havenDefaultNodeUri = 'nodes.havenprotocol.org:443';
const ethereumDefaultNodeUri = 'ethereum.publicnode.com';
const polygonDefaultNodeUri = 'polygon-bor.publicnode.com';
const cakeWalletBitcoinCashDefaultNodeUri = 'bitcoincash.stackwallet.com:50002';
const nanoDefaultNodeUri = 'rpc.nano.to';
const nanoDefaultPowNodeUri = 'rpc.nano.to';
@@ -64,6 +66,8 @@ Future<void> defaultSettingsMigration(
final migrationVersions =
List<int>.generate(migrationVersionsLength, (i) => currentVersion + (i + 1));
/// When you add a new case, increase the initialMigrationVersion parameter in the main.dart file.
/// This ensures that this switch case runs the newly added case.
await Future.forEach(migrationVersions, (int version) async {
try {
switch (version) {
@@ -82,8 +86,7 @@ Future<void> defaultSettingsMigration(
sharedPreferences: sharedPreferences, nodes: nodes);
await changeLitecoinCurrentElectrumServerToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
await changeHavenCurrentNodeToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
await changeHavenCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
await changeBitcoinCashCurrentNodeToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
@@ -175,6 +178,14 @@ Future<void> defaultSettingsMigration(
await changeBitcoinCurrentElectrumServerToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
break;
case 24:
await addPolygonNodeList(nodes: nodes);
await changePolygonCurrentNodeToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
break;
case 25:
await rewriteSecureStoragePin(secureStorage: secureStorage);
break;
default:
break;
@@ -329,6 +340,11 @@ Node? getEthereumDefaultNode({required Box<Node> nodes}) {
nodes.values.firstWhereOrNull((node) => node.type == WalletType.ethereum);
}
Node? getPolygonDefaultNode({required Box<Node> nodes}) {
return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == polygonDefaultNodeUri) ??
nodes.values.firstWhereOrNull((node) => node.type == WalletType.polygon);
}
Node? getNanoDefaultNode({required Box<Node> nodes}) {
return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == nanoDefaultNodeUri) ??
nodes.values.firstWhereOrNull((node) => node.type == WalletType.nano);
@@ -340,9 +356,9 @@ Node? getNanoDefaultPowNode({required Box<Node> nodes}) {
}
Node? getBitcoinCashDefaultElectrumServer({required Box<Node> nodes}) {
return nodes.values.firstWhereOrNull(
(Node node) => node.uriRaw == cakeWalletBitcoinCashDefaultNodeUri)
?? nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoinCash);
return nodes.values
.firstWhereOrNull((Node node) => node.uriRaw == cakeWalletBitcoinCashDefaultNodeUri) ??
nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoinCash);
}
Node getMoneroDefaultNode({required Box<Node> nodes}) {
@@ -364,6 +380,37 @@ Node getMoneroDefaultNode({required Box<Node> nodes}) {
}
}
Future<void> rewriteSecureStoragePin({required FlutterSecureStorage secureStorage}) async {
// the bug only affects ios/mac:
if (!Platform.isIOS && !Platform.isMacOS) {
return;
}
// first, get the encoded pin:
final keyForPinCode = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
String? encodedPin;
try {
encodedPin = await secureStorage.read(key: keyForPinCode);
} catch (e) {
// either we don't have a pin, or we can't read it (maybe even because of the bug!)
// the only option here is to abort the migration or we risk losing the pin and locking the user out
return;
}
if (encodedPin == null) {
return;
}
// ensure we overwrite by deleting the old key first:
await secureStorage.delete(key: keyForPinCode);
await secureStorage.write(
key: keyForPinCode,
value: encodedPin,
iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
mOptions: MacOsOptions(accessibility: KeychainAccessibility.first_unlock),
);
}
Future<void> changeBitcoinCurrentElectrumServerToDefault(
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
final server = getBitcoinDefaultElectrumServer(nodes: nodes);
@@ -381,8 +428,7 @@ Future<void> changeLitecoinCurrentElectrumServerToDefault(
}
Future<void> changeBitcoinCashCurrentNodeToDefault(
{required SharedPreferences sharedPreferences,
required Box<Node> nodes}) async {
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
final server = getBitcoinCashDefaultElectrumServer(nodes: nodes);
final serverId = server?.key as int ?? 0;
@@ -496,6 +542,7 @@ Future<void> generateBackupPassword(FlutterSecureStorage secureStorage) async {
}
final password = encrypt.Key.fromSecureRandom(32).base16;
await secureStorage.delete(key: key);
await secureStorage.write(key: key, value: password);
}
@@ -537,34 +584,33 @@ Future<void> checkCurrentNodes(
final currentMoneroNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
final currentBitcoinElectrumSeverId =
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
final currentLitecoinElectrumSeverId = sharedPreferences
.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
final currentHavenNodeId = sharedPreferences
.getInt(PreferencesKey.currentHavenNodeIdKey);
final currentEthereumNodeId = sharedPreferences
.getInt(PreferencesKey.currentEthereumNodeIdKey);
final currentNanoNodeId = sharedPreferences
.getInt(PreferencesKey.currentNanoNodeIdKey);
final currentNanoPowNodeId = sharedPreferences
.getInt(PreferencesKey.currentNanoPowNodeIdKey);
final currentBitcoinCashNodeId = sharedPreferences
.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
final currentMoneroNode = nodeSource.values.firstWhereOrNull(
(node) => node.key == currentMoneroNodeId);
final currentBitcoinElectrumServer = nodeSource.values.firstWhereOrNull(
(node) => node.key == currentBitcoinElectrumSeverId);
final currentLitecoinElectrumServer = nodeSource.values.firstWhereOrNull(
(node) => node.key == currentLitecoinElectrumSeverId);
final currentHavenNodeServer = nodeSource.values.firstWhereOrNull(
(node) => node.key == currentHavenNodeId);
final currentEthereumNodeServer = nodeSource.values.firstWhereOrNull(
(node) => node.key == currentEthereumNodeId);
final currentLitecoinElectrumSeverId =
sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
final currentHavenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
final currentEthereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
final currentPolygonNodeId = sharedPreferences.getInt(PreferencesKey.currentPolygonNodeIdKey);
final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
final currentNanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoPowNodeIdKey);
final currentBitcoinCashNodeId =
sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
final currentMoneroNode =
nodeSource.values.firstWhereOrNull((node) => node.key == currentMoneroNodeId);
final currentBitcoinElectrumServer =
nodeSource.values.firstWhereOrNull((node) => node.key == currentBitcoinElectrumSeverId);
final currentLitecoinElectrumServer =
nodeSource.values.firstWhereOrNull((node) => node.key == currentLitecoinElectrumSeverId);
final currentHavenNodeServer =
nodeSource.values.firstWhereOrNull((node) => node.key == currentHavenNodeId);
final currentEthereumNodeServer =
nodeSource.values.firstWhereOrNull((node) => node.key == currentEthereumNodeId);
final currentPolygonNodeServer =
nodeSource.values.firstWhereOrNull((node) => node.key == currentPolygonNodeId);
final currentNanoNodeServer =
nodeSource.values.firstWhereOrNull((node) => node.key == currentNanoNodeId);
nodeSource.values.firstWhereOrNull((node) => node.key == currentNanoNodeId);
final currentNanoPowNodeServer =
powNodeSource.values.firstWhereOrNull((node) => node.key == currentNanoPowNodeId);
final currentBitcoinCashNodeServer = nodeSource.values.firstWhereOrNull(
(node) => node.key == currentBitcoinCashNodeId);
powNodeSource.values.firstWhereOrNull((node) => node.key == currentNanoPowNodeId);
final currentBitcoinCashNodeServer =
nodeSource.values.firstWhereOrNull((node) => node.key == currentBitcoinCashNodeId);
if (currentMoneroNode == null) {
final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero);
await nodeSource.add(newCakeWalletNode);
@@ -616,8 +662,13 @@ Future<void> checkCurrentNodes(
if (currentBitcoinCashNodeServer == null) {
final node = Node(uri: cakeWalletBitcoinCashDefaultNodeUri, type: WalletType.bitcoinCash);
await nodeSource.add(node);
await sharedPreferences.setInt(
PreferencesKey.currentBitcoinCashNodeIdKey, node.key as int);
await sharedPreferences.setInt(PreferencesKey.currentBitcoinCashNodeIdKey, node.key as int);
}
if (currentPolygonNodeServer == null) {
final node = Node(uri: polygonDefaultNodeUri, type: WalletType.polygon);
await nodeSource.add(node);
await sharedPreferences.setInt(PreferencesKey.currentPolygonNodeIdKey, node.key as int);
}
}
@@ -713,3 +764,20 @@ Future<void> changeNanoCurrentPowNodeToDefault(
final nodeId = node?.key as int? ?? 0;
await sharedPreferences.setInt(PreferencesKey.currentNanoPowNodeIdKey, nodeId);
}
Future<void> addPolygonNodeList({required Box<Node> nodes}) async {
final nodeList = await loadDefaultPolygonNodes();
for (var node in nodeList) {
if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) {
await nodes.add(node);
}
}
}
Future<void> changePolygonCurrentNodeToDefault(
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
final node = getPolygonDefaultNode(nodes: nodes);
final nodeId = node?.key as int? ?? 0;
await sharedPreferences.setInt(PreferencesKey.currentPolygonNodeIdKey, nodeId);
}
+6
View File
@@ -1,4 +1,5 @@
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:ens_dart/ens_dart.dart';
@@ -12,6 +13,10 @@ class EnsRecord {
if (wallet != null && wallet.type == WalletType.ethereum) {
_client = ethereum!.getWeb3Client(wallet);
}
if (wallet != null && wallet.type == WalletType.polygon) {
_client = polygon!.getWeb3Client(wallet);
}
if (_client == null) {
_client = Web3Client("https://ethereum.publicnode.com", Client());
@@ -31,6 +36,7 @@ class EnsRecord {
case WalletType.haven:
return await ens.withName(name).getCoinAddress(CoinType.XHV);
case WalletType.ethereum:
case WalletType.polygon:
default:
return (await ens.withName(name).getAddress()).hex;
}
+1
View File
@@ -147,6 +147,7 @@ Future<void> ios_migrate_pin() async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final encodedPassword = encodedPinCode(pin: pinPassword);
await flutterSecureStorage.delete(key: key);
await flutterSecureStorage.write(key: key, value: encodedPassword);
await prefs.setBool('ios_migration_pin_completed', true);
}
+3 -1
View File
@@ -9,7 +9,9 @@ Future<List<int>> getEncryptionKey(
if (stringifiedKey == null) {
key = CakeHive.generateSecureKey();
final keyStringified = key.join(',');
await secureStorage.write(key: 'transactionDescriptionsBoxKey', value: keyStringified);
String storageKey = 'transactionDescriptionsBoxKey';
await secureStorage.delete(key: storageKey);
await secureStorage.write(key: storageKey, value: keyStringified);
} else {
key = stringifiedKey.split(',').map((i) => int.parse(i)).toList();
}
+47 -37
View File
@@ -1,3 +1,4 @@
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';
@@ -19,7 +20,8 @@ class MainActions {
final bool Function(DashboardViewModel viewModel)? isEnabled;
final bool Function(DashboardViewModel viewModel)? canShow;
final Future<void> Function(BuildContext context, DashboardViewModel viewModel) onTap;
final Future<void> Function(
BuildContext context, DashboardViewModel viewModel) onTap;
MainActions._({
required this.name,
@@ -43,47 +45,54 @@ class MainActions {
isEnabled: (viewModel) => viewModel.isEnabledBuyAction,
canShow: (viewModel) => viewModel.hasBuyAction,
onTap: (BuildContext context, DashboardViewModel viewModel) async {
if (!viewModel.isEnabledBuyAction) {
await _showErrorDialog(context, S.of(context).unsupported_asset);
return;
}
final defaultBuyProvider = viewModel.defaultBuyProvider;
final walletType = viewModel.type;
if (!viewModel.isEnabledBuyAction) return;
switch (walletType) {
case WalletType.bitcoin:
case WalletType.litecoin:
case WalletType.ethereum:
case WalletType.bitcoinCash:
switch (defaultBuyProvider) {
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;
}
break;
case WalletType.nano:
case WalletType.banano:
case WalletType.monero:
await getIt.get<OnRamperBuyProvider>().launchProvider(context);
break;
default:
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).buy,
alertContent: S.of(context).unsupported_asset,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
try {
await _launchProviderByType(context, defaultBuyProvider);
} catch (e) {
await _showErrorDialog(context, 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',
@@ -124,6 +133,7 @@ class MainActions {
case WalletType.bitcoin:
case WalletType.litecoin:
case WalletType.ethereum:
case WalletType.polygon:
case WalletType.bitcoinCash:
if (viewModel.isEnabledSellAction) {
final moonPaySellProvider = MoonPaySellProvider();
+20 -1
View File
@@ -133,6 +133,22 @@ Future<List<Node>> loadDefaultNanoPowNodes() async {
return nodes;
}
Future<List<Node>> loadDefaultPolygonNodes() async {
final nodesRaw = await rootBundle.loadString('assets/polygon_node_list.yml');
final loadedNodes = loadYaml(nodesRaw) as YamlList;
final nodes = <Node>[];
for (final raw in loadedNodes) {
if (raw is Map) {
final node = Node.fromMap(Map<String, Object>.from(raw));
node.type = WalletType.polygon;
nodes.add(node);
}
}
return nodes;
}
Future<void> resetToDefault(Box<Node> nodeSource) async {
final moneroNodes = await loadDefaultNodes();
final bitcoinElectrumServerList = await loadBitcoinElectrumServerList();
@@ -141,6 +157,8 @@ Future<void> resetToDefault(Box<Node> nodeSource) async {
final havenNodes = await loadDefaultHavenNodes();
final ethereumNodes = await loadDefaultEthereumNodes();
final nanoNodes = await loadDefaultNanoNodes();
final polygonNodes = await loadDefaultPolygonNodes();
final nodes = moneroNodes +
bitcoinElectrumServerList +
@@ -148,7 +166,8 @@ Future<void> resetToDefault(Box<Node> nodeSource) async {
havenNodes +
ethereumNodes +
bitcoinCashElectrumServerList +
nanoNodes;
nanoNodes +
polygonNodes;
await nodeSource.clear();
await nodeSource.addAll(nodes);
+4
View File
@@ -6,6 +6,7 @@ class PreferencesKey {
static const currentLitecoinElectrumSererIdKey = 'current_node_id_ltc';
static const currentHavenNodeIdKey = 'current_node_id_xhv';
static const currentEthereumNodeIdKey = 'current_node_id_eth';
static const currentPolygonNodeIdKey = 'current_node_id_matic';
static const currentNanoNodeIdKey = 'current_node_id_nano';
static const currentNanoPowNodeIdKey = 'current_node_id_nano_pow';
static const currentBananoNodeIdKey = 'current_node_id_banano';
@@ -37,6 +38,7 @@ class PreferencesKey {
static const havenTransactionPriority = 'current_fee_priority_haven';
static const litecoinTransactionPriority = 'current_fee_priority_litecoin';
static const ethereumTransactionPriority = 'current_fee_priority_ethereum';
static const polygonTransactionPriority = 'current_fee_priority_polygon';
static const bitcoinCashTransactionPriority = 'current_fee_priority_bitcoin_cash';
static const shouldShowReceiveWarning = 'should_show_receive_warning';
static const shouldShowYatPopup = 'should_show_yat_popup';
@@ -50,6 +52,7 @@ class PreferencesKey {
static const sortBalanceBy = 'sort_balance_by';
static const pinNativeTokenAtTop = 'pin_native_token_at_top';
static const useEtherscan = 'use_etherscan';
static const usePolygonScan = 'use_polygonscan';
static const defaultNanoRep = 'default_nano_representative';
static const defaultBananoRep = 'default_banano_representative';
static const lookupsTwitter = 'looks_up_twitter';
@@ -64,6 +67,7 @@ class PreferencesKey {
static const exchangeProvidersSelection = 'exchange-providers-selection';
static const autoGenerateSubaddressStatusKey = 'auto_generate_subaddress_status';
static const moneroSeedType = 'monero_seed_type';
static const clearnetDonationLink = 'clearnet_donation_link';
static const onionDonationLink = 'onion_donation_link';
static const lastSeenAppVersion = 'last_seen_app_version';
@@ -3,6 +3,7 @@ import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/haven/haven.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_type.dart';
@@ -24,6 +25,8 @@ List<TransactionPriority> priorityForWalletType(WalletType type) {
case WalletType.nano:
case WalletType.banano:
return [];
case WalletType.polygon:
return polygon!.getTransactionPriorities();
default:
return [];
}
+36
View File
@@ -0,0 +1,36 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cw_core/enumerable_item.dart';
class SeedType extends EnumerableItem<int> with Serializable<int> {
const SeedType({required String title, required int raw}) : super(title: title, raw: raw);
static const all = [SeedType.legacy, SeedType.polyseed];
static const defaultSeedType = polyseed;
static const legacy = SeedType(raw: 0, title: 'Legacy (25 words)');
static const polyseed = SeedType(raw: 1, title: 'Polyseed (16 words)');
static SeedType deserialize({required int raw}) {
switch (raw) {
case 0:
return legacy;
case 1:
return polyseed;
default:
throw Exception('Unexpected token: $raw for SeedType deserialize');
}
}
@override
String toString() {
switch (this) {
case SeedType.legacy:
return S.current.seedtype_legacy;
case SeedType.polyseed:
return S.current.seedtype_polyseed;
default:
return '';
}
}
}
+1 -1
View File
@@ -163,7 +163,7 @@ Future<void> initializeAppConfigs() async {
transactionDescriptions: transactionDescriptions,
secureStorage: secureStorage,
anonpayInvoiceInfo: anonpayInvoiceInfo,
initialMigrationVersion: 23);
initialMigrationVersion: 25);
}
Future<void> initialSetup(
+7 -1
View File
@@ -166,6 +166,10 @@ class CWMonero extends Monero {
@override
List<String> getMoneroWordList(String language) {
if (language.startsWith("POLYSEED_")) {
final lang = language.replaceAll("POLYSEED_", "");
return PolyseedLang.getByEnglishName(lang).words;
}
switch (language.toLowerCase()) {
case 'english':
return EnglishMnemonics.words;
@@ -223,8 +227,10 @@ class CWMonero extends Monero {
WalletCredentials createMoneroNewWalletCredentials({
required String name,
required String language,
required bool isPolyseed,
String? password}) =>
MoneroNewWalletCredentials(name: name, password: password, language: language);
MoneroNewWalletCredentials(
name: name, password: password, language: language, isPolyseed: isPolyseed);
@override
Map<String, String> getKeys(Object wallet) {
+156
View File
@@ -0,0 +1,156 @@
part of 'polygon.dart';
class CWPolygon extends Polygon {
@override
List<String> getPolygonWordList(String language) => EthereumMnemonics.englishWordlist;
WalletService createPolygonWalletService(Box<WalletInfo> walletInfoSource) =>
PolygonWalletService(walletInfoSource);
@override
WalletCredentials createPolygonNewWalletCredentials({
required String name,
WalletInfo? walletInfo,
}) =>
PolygonNewWalletCredentials(name: name, walletInfo: walletInfo);
@override
WalletCredentials createPolygonRestoreWalletFromSeedCredentials({
required String name,
required String mnemonic,
required String password,
}) =>
PolygonRestoreWalletFromSeedCredentials(name: name, password: password, mnemonic: mnemonic);
@override
WalletCredentials createPolygonRestoreWalletFromPrivateKey({
required String name,
required String privateKey,
required String password,
}) =>
PolygonRestoreWalletFromPrivateKey(name: name, password: password, privateKey: privateKey);
@override
String getAddress(WalletBase wallet) => (wallet as PolygonWallet).walletAddresses.address;
@override
String getPrivateKey(WalletBase wallet) {
final privateKeyHolder = (wallet as PolygonWallet).polygonPrivateKey;
String stringKey = bytesToHex(privateKeyHolder.privateKey);
return stringKey;
}
@override
String getPublicKey(WalletBase wallet) {
final privateKeyInUnitInt = (wallet as PolygonWallet).polygonPrivateKey;
final publicKey = privateKeyInUnitInt.address.hex;
return publicKey;
}
@override
TransactionPriority getDefaultTransactionPriority() => PolygonTransactionPriority.medium;
@override
TransactionPriority getPolygonTransactionPrioritySlow() => PolygonTransactionPriority.slow;
@override
List<TransactionPriority> getTransactionPriorities() => PolygonTransactionPriority.all;
@override
TransactionPriority deserializePolygonTransactionPriority(int raw) =>
PolygonTransactionPriority.deserialize(raw: raw);
Object createPolygonTransactionCredentials(
List<Output> outputs, {
required TransactionPriority priority,
required CryptoCurrency currency,
int? feeRate,
}) =>
PolygonTransactionCredentials(
outputs
.map((out) => OutputInfo(
fiatAmount: out.fiatAmount,
cryptoAmount: out.cryptoAmount,
address: out.address,
note: out.note,
sendAll: out.sendAll,
extractedAddress: out.extractedAddress,
isParsedAddress: out.isParsedAddress,
formattedCryptoAmount: out.formattedCryptoAmount))
.toList(),
priority: priority as PolygonTransactionPriority,
currency: currency,
feeRate: feeRate,
);
Object createPolygonTransactionCredentialsRaw(
List<OutputInfo> outputs, {
TransactionPriority? priority,
required CryptoCurrency currency,
required int feeRate,
}) =>
PolygonTransactionCredentials(
outputs,
priority: priority as PolygonTransactionPriority?,
currency: currency,
feeRate: feeRate,
);
@override
int formatterPolygonParseAmount(String amount) => PolygonFormatter.parsePolygonAmount(amount);
@override
double formatterPolygonAmountToDouble(
{TransactionInfo? transaction, BigInt? amount, int exponent = 18}) {
assert(transaction != null || amount != null);
if (transaction != null) {
transaction as PolygonTransactionInfo;
return transaction.ethAmount / BigInt.from(10).pow(transaction.exponent);
} else {
return (amount!) / BigInt.from(10).pow(exponent);
}
}
@override
List<Erc20Token> getERC20Currencies(WalletBase wallet) {
final polygonWallet = wallet as PolygonWallet;
return polygonWallet.erc20Currencies;
}
@override
Future<void> addErc20Token(WalletBase wallet, Erc20Token token) async =>
await (wallet as PolygonWallet).addErc20Token(token);
@override
Future<void> deleteErc20Token(WalletBase wallet, Erc20Token token) async =>
await (wallet as PolygonWallet).deleteErc20Token(token);
@override
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async {
final polygonWallet = wallet as PolygonWallet;
return await polygonWallet.getErc20Token(contractAddress);
}
@override
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction) {
transaction as PolygonTransactionInfo;
if (transaction.tokenSymbol == CryptoCurrency.maticpoly.title) {
return CryptoCurrency.maticpoly;
}
wallet as PolygonWallet;
return wallet.erc20Currencies.firstWhere(
(element) => transaction.tokenSymbol.toLowerCase() == element.symbol.toLowerCase());
}
@override
void updatePolygonScanUsageState(WalletBase wallet, bool isEnabled) {
(wallet as PolygonWallet).updatePolygonScanUsageState(isEnabled);
}
@override
Web3Client? getWeb3Client(WalletBase wallet) {
return (wallet as PolygonWallet).getWeb3Client();
}
}
+12 -2
View File
@@ -3,9 +3,11 @@ import 'package:cake_wallet/core/fiat_conversion_service.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/update_haven_rate.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cw_core/erc20_token.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart';
@@ -33,10 +35,18 @@ Future<void> startFiatRateUpdate(
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly);
}
Iterable<Erc20Token>? currencies;
if (appStore.wallet!.type == WalletType.ethereum) {
final currencies =
ethereum!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
currencies =
ethereum!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
}
if (appStore.wallet!.type == WalletType.polygon) {
currencies =
polygon!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
}
if (currencies != null) {
for (final currency in currencies) {
() async {
fiatConversionStore.prices[currency] = await FiatConversionService.fetchPrice(
+10 -2
View File
@@ -2,7 +2,8 @@ import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/update_haven_rate.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cw_core/erc20_token.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/balance.dart';
import 'package:cw_core/transaction_info.dart';
@@ -107,10 +108,17 @@ void startCurrentWalletChangeReaction(
fiat: settingsStore.fiatCurrency,
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly);
Iterable<Erc20Token>? currencies;
if (wallet.type == WalletType.ethereum) {
final currencies =
currencies =
ethereum!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
}
if (wallet.type == WalletType.polygon) {
currencies =
polygon!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
}
if (currencies != null) {
for (final currency in currencies) {
() async {
fiatConversionStore.prices[currency] = await FiatConversionService.fetchPrice(
+46
View File
@@ -0,0 +1,46 @@
import 'package:cake_wallet/core/wallet_connect/evm_chain_id.dart';
import 'package:cw_core/wallet_type.dart';
bool isEVMCompatibleChain(WalletType walletType) {
switch (walletType) {
case WalletType.polygon:
case WalletType.ethereum:
return true;
default:
return false;
}
}
String getChainNameSpaceAndIdBasedOnWalletType(WalletType walletType) {
switch (walletType) {
case WalletType.ethereum:
return EVMChainId.ethereum.chain();
case WalletType.polygon:
return EVMChainId.polygon.chain();
default:
return '';
}
}
int getChainIdBasedOnWalletType(WalletType walletType) {
switch (walletType) {
case WalletType.polygon:
return 137;
// For now, we return eth chain Id as the default, we'll modify as we add more wallets
case WalletType.ethereum:
default:
return 1;
}
}
String getChainNameBasedOnWalletType(WalletType walletType) {
switch (walletType) {
case WalletType.ethereum:
return 'eth';
case WalletType.polygon:
return 'polygon';
default:
return '';
}
}
+6 -16
View File
@@ -62,6 +62,7 @@ import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cw_core/nano_account.dart';
import 'package:cw_core/wallet_info.dart';
@@ -87,7 +88,6 @@ import 'package:cake_wallet/src/screens/setup_pin_code/setup_pin_code.dart';
import 'package:cake_wallet/src/screens/restore/restore_options_page.dart';
import 'package:cake_wallet/src/screens/send/send_page.dart';
import 'package:cake_wallet/src/screens/disclaimer/disclaimer_page.dart';
import 'package:cake_wallet/src/screens/seed_language/seed_language_page.dart';
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_page.dart';
import 'package:cake_wallet/src/screens/monero_accounts/monero_account_edit_or_create_page.dart';
import 'package:cake_wallet/src/screens/contact/contact_list_page.dart';
@@ -147,8 +147,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.newWallet:
final type = settings.arguments as WalletType;
final walletNewVM = getIt.get<WalletNewVM>(param1: type);
final seedTypeViewModel = getIt.get<SeedTypeViewModel>();
return CupertinoPageRoute<void>(builder: (_) => NewWalletPage(walletNewVM));
return CupertinoPageRoute<void>(builder: (_) => NewWalletPage(walletNewVM, seedTypeViewModel));
case Routes.setupPin:
Function(PinCodeState<PinCodeWidget>, String)? callback;
@@ -264,17 +265,6 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.changeRep:
return CupertinoPageRoute<void>(builder: (_) => getIt.get<NanoChangeRepPage>());
case Routes.seedLanguage:
final args = settings.arguments as List<dynamic>;
final type = args.first as WalletType;
final redirectRoute = args[1] as String;
return CupertinoPageRoute<void>(builder: (_) {
return SeedLanguage(
onConfirm: (context, lang) =>
Navigator.of(context).popAndPushNamed(redirectRoute, arguments: [type, lang]));
});
case Routes.walletList:
return MaterialPageRoute<void>(
fullscreenDialog: true, builder: (_) => getIt.get<WalletListPage>());
@@ -543,9 +533,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
return CupertinoPageRoute<void>(
builder: (_) => AdvancedPrivacySettingsPage(
getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
getIt.get<NodeCreateOrEditViewModel>(param1: type, param2: false),
));
getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
getIt.get<NodeCreateOrEditViewModel>(param1: type, param2: false),
getIt.get<SeedTypeViewModel>()));
case Routes.anonPayInvoicePage:
final args = settings.arguments as List;
-1
View File
@@ -18,7 +18,6 @@ class Routes {
static const disclaimer = '/disclaimer';
static const readDisclaimer = '/read_disclaimer';
static const changeRep = '/change_representative';
static const seedLanguage = '/seed_language';
static const walletList = '/view_model.wallet_list';
static const auth = '/auth';
static const newNode = '/new_node_list';
+58 -24
View File
@@ -1,18 +1,26 @@
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/entities/buy_provider_types.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/option_tile.dart';
import 'package:cake_wallet/themes/extensions/option_tile_theme.dart';
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);
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';
@override
String get title => S.current.buy;
@@ -22,11 +30,19 @@ class BuyOptionsPage extends BasePage {
@override
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 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;
return Container(
child: Center(
@@ -34,26 +50,42 @@ class BuyOptionsPage extends BasePage {
constraints: BoxConstraints(maxWidth: 330),
child: Column(
children: [
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.Onramper))
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),
),
),
),
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.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),
),
),
),
Spacer(),
Padding(
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
@@ -63,7 +95,9 @@ class BuyOptionsPage extends BasePage {
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
color: Theme.of(context)
.extension<TransactionTradeTheme>()!
.detailsTitlesColor,
),
),
),
@@ -191,7 +191,10 @@ class _DashboardPageView extends BasePage {
radius: 6.0,
dotWidth: 6.0,
dotHeight: 6.0,
dotColor: Theme.of(context).indicatorColor,
dotColor: Theme.of(context)
.extension<DashboardPageTheme>()!
.indicatorDotTheme
.indicatorColor,
activeDotColor: Theme.of(context)
.extension<DashboardPageTheme>()!
.indicatorDotTheme
@@ -33,6 +33,7 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
final ethereumIcon = Image.asset('assets/images/eth_icon.png', height: 24, width: 24);
final polygonIcon = Image.asset('assets/images/matic_icon.png', height: 24, width: 24);
final bitcoinCashIcon = Image.asset('assets/images/bch_icon.png', height: 24, width: 24);
final nanoIcon = Image.asset('assets/images/nano_icon.png', height: 24, width: 24);
final bananoIcon = Image.asset('assets/images/nano_icon.png', height: 24, width: 24);
@@ -150,6 +151,8 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
return nanoIcon;
case WalletType.banano:
return bananoIcon;
case WalletType.polygon:
return polygonIcon;
default:
return nonWalletTypeIcon;
}
@@ -1,5 +1,6 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/nft_listing_page.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/home_screen_account_widget.dart';
@@ -13,7 +14,6 @@ import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -32,12 +32,12 @@ class BalancePage extends StatelessWidget {
Widget build(BuildContext context) {
return Observer(
builder: (context) {
final isEthereumWallet = dashboardViewModel.type == WalletType.ethereum;
final isEVMCompatible = isEVMCompatibleChain(dashboardViewModel.type);
return DefaultTabController(
length: isEthereumWallet ? 2 : 1,
length: isEVMCompatible ? 2 : 1,
child: Column(
children: [
if (isEthereumWallet)
if (isEVMCompatible)
Align(
alignment: Alignment.centerLeft,
child: Padding(
@@ -66,7 +66,7 @@ class BalancePage extends StatelessWidget {
physics: NeverScrollableScrollPhysics(),
children: [
CryptoBalanceWidget(dashboardViewModel: dashboardViewModel),
if (isEthereumWallet) NFTListingPage(nftViewModel: nftViewModel)
if (isEVMCompatible) NFTListingPage(nftViewModel: nftViewModel)
],
),
),
@@ -32,7 +32,8 @@ class MenuWidgetState extends State<MenuWidget> {
this.ethereumIcon = Image.asset('assets/images/eth_icon.png'),
this.nanoIcon = Image.asset('assets/images/nano_icon.png'),
this.bananoIcon = Image.asset('assets/images/nano_icon.png'),
this.bitcoinCashIcon = Image.asset('assets/images/bch_icon.png');
this.bitcoinCashIcon = Image.asset('assets/images/bch_icon.png'),
this.polygonIcon = Image.asset('assets/images/matic_icon.png');
final largeScreen = 731;
@@ -54,6 +55,8 @@ class MenuWidgetState extends State<MenuWidget> {
Image bitcoinCashIcon;
Image nanoIcon;
Image bananoIcon;
Image polygonIcon;
@override
void initState() {
@@ -219,6 +222,8 @@ class MenuWidgetState extends State<MenuWidget> {
return nanoIcon;
case WalletType.banano:
return bananoIcon;
case WalletType.polygon:
return polygonIcon;
default:
throw Exception('No icon for ${type.toString()}');
}
@@ -1,6 +1,7 @@
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/seed_phrase_length.dart';
import 'package:cake_wallet/entities/seed_type.dart';
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
@@ -8,6 +9,7 @@ import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter/material.dart';
@@ -17,25 +19,30 @@ import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
class AdvancedPrivacySettingsPage extends BasePage {
AdvancedPrivacySettingsPage(this.advancedPrivacySettingsViewModel, this.nodeViewModel);
AdvancedPrivacySettingsPage(
this.advancedPrivacySettingsViewModel, this.nodeViewModel, this.seedTypeViewModel);
final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel;
final NodeCreateOrEditViewModel nodeViewModel;
final SeedTypeViewModel seedTypeViewModel;
@override
String get title => S.current.privacy_settings;
@override
Widget body(BuildContext context) =>
AdvancedPrivacySettingsBody(advancedPrivacySettingsViewModel, nodeViewModel);
Widget body(BuildContext context) => AdvancedPrivacySettingsBody(
advancedPrivacySettingsViewModel, nodeViewModel, seedTypeViewModel);
}
class AdvancedPrivacySettingsBody extends StatefulWidget {
const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, this.nodeViewModel, {Key? key})
const AdvancedPrivacySettingsBody(
this.privacySettingsViewModel, this.nodeViewModel, this.seedTypeViewModel,
{Key? key})
: super(key: key);
final AdvancedPrivacySettingsViewModel privacySettingsViewModel;
final NodeCreateOrEditViewModel nodeViewModel;
final SeedTypeViewModel seedTypeViewModel;
@override
_AdvancedPrivacySettingsBodyState createState() => _AdvancedPrivacySettingsBodyState();
@@ -58,7 +65,7 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
Observer(builder: (_) {
return SettingsChoicesCell(
ChoicesListItem<FiatApiMode>(
title: S.current.disable_fiat,
title: S.current.fiat_api,
items: FiatApiMode.all,
selectedItem: widget.privacySettingsViewModel.fiatApiMode,
onItemSelected: (FiatApiMode mode) =>
@@ -97,16 +104,27 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
);
}),
if (widget.privacySettingsViewModel.hasSeedPhraseLengthOption)
Observer(builder: (_) {
return SettingsPickerCell<SeedPhraseLength>(
title: S.current.seed_phrase_length,
items: SeedPhraseLength.values,
selectedItem: widget.privacySettingsViewModel.seedPhraseLength,
onItemSelected: (SeedPhraseLength length) {
widget.privacySettingsViewModel.setSeedPhraseLength(length);
},
);
}),
Observer(builder: (_) {
return SettingsPickerCell<SeedPhraseLength>(
title: S.current.seed_phrase_length,
items: SeedPhraseLength.values,
selectedItem: widget.privacySettingsViewModel.seedPhraseLength,
onItemSelected: (SeedPhraseLength length) {
widget.privacySettingsViewModel.setSeedPhraseLength(length);
},
);
}),
if (widget.privacySettingsViewModel.hasSeedTypeOption)
Observer(builder: (_) {
return SettingsChoicesCell(
ChoicesListItem<SeedType>(
title: S.current.seedtype,
items: SeedType.all,
selectedItem: widget.seedTypeViewModel.moneroSeedType,
onItemSelected: widget.seedTypeViewModel.setMoneroSeedType,
),
);
}),
],
),
bottomSectionPadding: EdgeInsets.all(24),
+64 -24
View File
@@ -1,10 +1,13 @@
import 'package:cake_wallet/entities/generate_name.dart';
import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/main.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
import 'package:mobx/mobx.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter/material.dart';
@@ -14,17 +17,19 @@ import 'package:cake_wallet/src/widgets/seed_language_selector.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart';
import 'package:cake_wallet/src/widgets/seed_language_picker.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
import 'package:cake_wallet/entities/seed_type.dart';
class NewWalletPage extends BasePage {
NewWalletPage(this._walletNewVM);
NewWalletPage(this._walletNewVM, this._seedTypeViewModel);
final WalletNewVM _walletNewVM;
final SeedTypeViewModel _seedTypeViewModel;
final walletNameImage = Image.asset('assets/images/wallet_name.png');
@@ -35,14 +40,15 @@ class NewWalletPage extends BasePage {
@override
Widget body(BuildContext context) => WalletNameForm(
_walletNewVM, currentTheme.type == ThemeType.dark ? walletNameImage : walletNameLightImage);
_walletNewVM, currentTheme.type == ThemeType.dark ? walletNameImage : walletNameLightImage, _seedTypeViewModel);
}
class WalletNameForm extends StatefulWidget {
WalletNameForm(this._walletNewVM, this.walletImage);
WalletNameForm(this._walletNewVM, this.walletImage, this._seedTypeViewModel);
final WalletNewVM _walletNewVM;
final Image walletImage;
final SeedTypeViewModel _seedTypeViewModel;
@override
_WalletNameFormState createState() => _WalletNameFormState(_walletNewVM);
@@ -84,6 +90,8 @@ class _WalletNameFormState extends State<WalletNameForm> {
});
}
});
_setSeedType(SeedType.defaultSeedType);
super.initState();
}
@@ -125,15 +133,20 @@ class _WalletNameFormState extends State<WalletNameForm> {
hintStyle: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.w500,
color: Theme.of(context).extension<NewWalletTheme>()!.hintTextColor),
color:
Theme.of(context).extension<NewWalletTheme>()!.hintTextColor),
hintText: S.of(context).wallet_name,
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).extension<NewWalletTheme>()!.underlineColor,
color: Theme.of(context)
.extension<NewWalletTheme>()!
.underlineColor,
width: 1.0)),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).extension<NewWalletTheme>()!.underlineColor,
color: Theme.of(context)
.extension<NewWalletTheme>()!
.underlineColor,
width: 1.0),
),
suffixIcon: Semantics(
@@ -160,7 +173,9 @@ class _WalletNameFormState extends State<WalletNameForm> {
height: 34,
child: Image.asset(
'assets/images/refresh_icon.png',
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonIconColor,
color: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldButtonIconColor,
),
),
),
@@ -172,22 +187,40 @@ class _WalletNameFormState extends State<WalletNameForm> {
),
),
),
if (_walletNewVM.hasLanguageSelector) ...[
Padding(
padding: EdgeInsets.only(top: 40),
child: Text(
S.of(context).seed_language_choose,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.w500,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
if (_walletNewVM.hasSeedType) ...[
Observer(
builder: (BuildContext build) => Padding(
padding: EdgeInsets.only(top: 24),
child: SelectButton(
text: widget._seedTypeViewModel.moneroSeedType.title,
onTap: () async {
await showPopUp<void>(
context: context,
builder: (_) => Picker(
items: SeedType.all,
selectedAtIndex: isPolyseed ? 1 : 0,
onItemSelected: _setSeedType,
isSeparated: false,
),
);
},
),
),
),
],
Observer(
builder: (BuildContext build) => Padding(
padding: EdgeInsets.only(top: 10),
child: SeedLanguageSelector(
key: _languageSelectorKey,
initialSelected: defaultSeedLanguage,
seedType: _walletNewVM.hasSeedType
? widget._seedTypeViewModel.moneroSeedType
: SeedType.legacy,
),
),
),
Padding(
padding: EdgeInsets.only(top: 24),
child: SeedLanguageSelector(
key: _languageSelectorKey, initialSelected: defaultSeedLanguage),
)
]
],
@@ -215,7 +248,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
Navigator.of(context)
.pushNamed(Routes.advancedPrivacySettings, arguments: _walletNewVM.type);
},
child: Text(S.of(context).advanced_privacy_settings),
child: Text(S.of(context).advanced_settings),
),
],
)),
@@ -239,8 +272,15 @@ class _WalletNameFormState extends State<WalletNameForm> {
} else {
_walletNewVM.create(
options: _walletNewVM.hasLanguageSelector
? _languageSelectorKey.currentState!.selected
? [_languageSelectorKey.currentState!.selected, isPolyseed]
: null);
}
}
bool get isPolyseed => widget._seedTypeViewModel.moneroSeedType == SeedType.polyseed;
void _setSeedType(SeedType item) {
widget._seedTypeViewModel.setMoneroSeedType(item);
_languageSelectorKey.currentState?.selected = defaultSeedLanguage; // Reset Seed language
}
}
@@ -1,5 +1,6 @@
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/currency.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -23,6 +24,13 @@ class CurrencyInputField extends StatelessWidget {
final TextEditingController controller;
final bool isLight;
String get _currencyName {
if (selectedCurrency is CryptoCurrency) {
return (selectedCurrency as CryptoCurrency).title.toUpperCase();
}
return selectedCurrency.name.toUpperCase();
}
@override
Widget build(BuildContext context) {
final arrowBottomPurple = Image.asset(
@@ -74,7 +82,7 @@ class CurrencyInputField extends StatelessWidget {
child: arrowBottomPurple,
),
Text(
selectedCurrency.name.toUpperCase(),
_currencyName,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
@@ -83,7 +91,7 @@ class CurrencyInputField extends StatelessWidget {
),
if (selectedCurrency.tag != null)
Padding(
padding: const EdgeInsets.only(right: 3.0),
padding: const EdgeInsets.symmetric(horizontal: 3.0),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
@@ -133,7 +133,7 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
widget.walletRestoreViewModel.type == WalletType.banano;
return AddressTextField(
controller: privateKeyController,
placeholder: nanoBased ? S.of(context).seed_key : S.of(context).private_key,
placeholder: nanoBased ? S.of(context).seed_hex_form : S.of(context).private_key,
options: [AddressTextFieldOption.paste],
buttonColor: Theme.of(context).hintColor,
onPushPasteButton: (_) {
@@ -1,17 +1,19 @@
import 'package:cake_wallet/core/wallet_name_validator.dart';
import 'package:cake_wallet/entities/generate_name.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart';
import 'package:cake_wallet/src/widgets/seed_widget.dart';
import 'package:cake_wallet/entities/seed_type.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/wallet_name_validator.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/src/widgets/seed_language_picker.dart';
import 'package:cake_wallet/src/widgets/seed_widget.dart';
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:mobx/mobx.dart';
import 'package:polyseed/polyseed.dart';
class WalletRestoreFromSeedForm extends StatefulWidget {
WalletRestoreFromSeedForm(
@@ -19,6 +21,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
required this.displayLanguageSelector,
required this.displayBlockHeightSelector,
required this.type,
required this.seedTypeViewModel,
this.blockHeightFocusNode,
this.onHeightOrDateEntered,
this.onSeedChange,
@@ -28,14 +31,14 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
final WalletType type;
final bool displayLanguageSelector;
final bool displayBlockHeightSelector;
final SeedTypeViewModel seedTypeViewModel;
final FocusNode? blockHeightFocusNode;
final Function(bool)? onHeightOrDateEntered;
final void Function(String)? onSeedChange;
final void Function(String)? onLanguageChange;
@override
WalletRestoreFromSeedFormState createState() =>
WalletRestoreFromSeedFormState('English');
WalletRestoreFromSeedFormState createState() => WalletRestoreFromSeedFormState('English');
}
class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
@@ -44,104 +47,189 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
formKey = GlobalKey<FormState>(),
languageController = TextEditingController(),
nameTextEditingController = TextEditingController();
nameTextEditingController = TextEditingController(),
seedTypeController = TextEditingController();
final GlobalKey<SeedWidgetState> seedWidgetStateKey;
final GlobalKey<BlockchainHeightState> blockchainHeightKey;
final TextEditingController languageController;
final TextEditingController nameTextEditingController;
final TextEditingController seedTypeController;
final GlobalKey<FormState> formKey;
late ReactionDisposer moneroSeedTypeReaction;
String language;
@override
void initState() {
_setSeedType(widget.seedTypeViewModel.moneroSeedType);
_setLanguageLabel(language);
moneroSeedTypeReaction =
reaction((_) => widget.seedTypeViewModel.moneroSeedType, (SeedType item) {
_setSeedType(item);
_changeLanguage('English');
});
super.initState();
}
@override
void dispose() {
super.dispose();
moneroSeedTypeReaction();
}
void onSeedChange(String seed) {
if (widget.type == WalletType.monero && Polyseed.isValidSeed(seed)) {
final lang = PolyseedLang.getByPhrase(seed);
_changeSeedType(SeedType.polyseed);
_changeLanguage(lang.nameEnglish);
}
widget.onSeedChange?.call(seed);
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(left: 24, right: 24),
child: Column(children: [
Form(
key: formKey,
child: Stack(
alignment: Alignment.centerRight,
children: [
BaseTextFormField(
controller: nameTextEditingController,
hintText: S.of(context).wallet_name,
suffixIcon: IconButton(
onPressed: () async {
final rName = await generateName();
FocusManager.instance.primaryFocus?.unfocus();
key: formKey,
child: Stack(
alignment: Alignment.centerRight,
children: [
BaseTextFormField(
controller: nameTextEditingController,
hintText: S.of(context).wallet_name,
suffixIcon: IconButton(
onPressed: () async {
final rName = await generateName();
FocusManager.instance.primaryFocus?.unfocus();
setState(() {
nameTextEditingController.text = rName;
nameTextEditingController.selection =
TextSelection.fromPosition(TextPosition(
offset: nameTextEditingController.text.length));
});
},
icon: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
color: Theme.of(context).hintColor,
),
width: 34,
height: 34,
child: Image.asset(
'assets/images/refresh_icon.png',
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonIconColor,
setState(() {
nameTextEditingController.text = rName;
nameTextEditingController.selection = TextSelection.fromPosition(
TextPosition(offset: nameTextEditingController.text.length));
});
},
icon: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
color: Theme.of(context).hintColor,
),
width: 34,
height: 34,
child: Image.asset(
'assets/images/refresh_icon.png',
color: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldButtonIconColor,
),
),
),
validator: WalletNameValidator(),
),
),
validator: WalletNameValidator(),
),
],
)),
],
)),
Container(height: 20),
SeedWidget(
key: seedWidgetStateKey,
language: language,
type: widget.type,
onSeedChange: widget.onSeedChange),
onSeedChange: onSeedChange),
if (widget.type == WalletType.monero)
GestureDetector(
onTap: () async {
await showPopUp<void>(
context: context,
builder: (_) => Picker(
items: SeedType.all,
selectedAtIndex: isPolyseed ? 1 : 0,
mainAxisAlignment: MainAxisAlignment.start,
onItemSelected: _changeSeedType,
isSeparated: false,
));
},
child: Container(
color: Colors.transparent,
padding: EdgeInsets.only(top: 20.0),
child: IgnorePointer(
child: BaseTextFormField(
controller: seedTypeController,
enableInteractiveSelection: false,
readOnly: true,
suffixIcon: expandIcon,
),
),
),
),
if (widget.displayLanguageSelector)
GestureDetector(
onTap: () async {
await showPopUp<void>(
context: context,
builder: (_) => SeedLanguagePicker(
selected: language, onItemSelected: _changeLanguage));
selected: language,
onItemSelected: _changeLanguage,
seedType: isPolyseed ? SeedType.polyseed : SeedType.legacy,
));
},
child: Container(
color: Colors.transparent,
padding: EdgeInsets.only(top: 20.0),
child: IgnorePointer(
child: BaseTextFormField(
controller: languageController,
enableInteractiveSelection: false,
readOnly: true)))),
if (widget.displayBlockHeightSelector)
child: Container(
color: Colors.transparent,
padding: EdgeInsets.only(top: 20.0),
child: IgnorePointer(
child: BaseTextFormField(
controller: languageController,
enableInteractiveSelection: false,
readOnly: true,
suffixIcon: expandIcon,
),
),
),
),
if (!isPolyseed && widget.displayBlockHeightSelector)
BlockchainHeightWidget(
focusNode: widget.blockHeightFocusNode,
key: blockchainHeightKey,
onHeightOrDateEntered: widget.onHeightOrDateEntered,
hasDatePicker: widget.type == WalletType.monero)
hasDatePicker: widget.type == WalletType.monero),
]));
}
bool get isPolyseed => widget.seedTypeViewModel.moneroSeedType == SeedType.polyseed;
Widget get expandIcon => Container(
padding: EdgeInsets.all(18),
width: 24,
height: 24,
child: Image.asset(
'assets/images/arrow_bottom_purple_icon.png',
height: 8,
color: Theme.of(context).hintColor,
),
);
void _changeLanguage(String language) {
final setLang = isPolyseed ? "POLYSEED_$language" : language;
setState(() {
this.language = language;
seedWidgetStateKey.currentState!.changeSeedLanguage(language);
_setLanguageLabel(language);
widget.onLanguageChange?.call(language);
this.language = setLang;
seedWidgetStateKey.currentState!.changeSeedLanguage(setLang);
_setLanguageLabel(setLang);
widget.onLanguageChange?.call(setLang);
});
}
void _setLanguageLabel(String language) =>
languageController.text = '$language (Seed language)';
languageController.text = '${language.replaceAll("POLYSEED_", "")} (Seed language)';
void _changeSeedType(SeedType item) {
_setSeedType(item);
_changeLanguage('English');
widget.seedTypeViewModel.setMoneroSeedType(item);
}
void _setSeedType(SeedType item) {
seedTypeController.text = item.toString();
}
}
@@ -1,32 +1,34 @@
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/restore/wallet_restore_from_keys_form.dart';
import 'package:cake_wallet/src/screens/restore/wallet_restore_from_seed_form.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
import 'package:cw_core/nano_account_info_response.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
import 'package:mobx/mobx.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:polyseed/polyseed.dart';
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
import 'package:cake_wallet/src/screens/restore/wallet_restore_from_keys_form.dart';
import 'package:cake_wallet/src/screens/restore/wallet_restore_from_seed_form.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
class WalletRestorePage extends BasePage {
WalletRestorePage(this.walletRestoreViewModel)
WalletRestorePage(this.walletRestoreViewModel, this.seedTypeViewModel)
: walletRestoreFromSeedFormKey = GlobalKey<WalletRestoreFromSeedFormState>(),
walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFromState>(),
_pages = [],
@@ -36,6 +38,7 @@ class WalletRestorePage extends BasePage {
switch (mode) {
case WalletRestoreMode.seed:
_pages.add(WalletRestoreFromSeedForm(
seedTypeViewModel: seedTypeViewModel,
displayBlockHeightSelector:
walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
displayLanguageSelector: walletRestoreViewModel.hasSeedLanguageSelector,
@@ -48,27 +51,13 @@ class WalletRestorePage extends BasePage {
}
},
onSeedChange: (String seed) {
if (walletRestoreViewModel.hasBlockchainHeightLanguageSelector) {
final hasHeight = walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey
.currentState!.restoreHeightController.text.isNotEmpty;
if (hasHeight) {
walletRestoreViewModel.isButtonEnabled = _isValidSeed();
}
} else {
walletRestoreViewModel.isButtonEnabled = _isValidSeed();
}
final isPolyseed =
walletRestoreViewModel.type == WalletType.monero && Polyseed.isValidSeed(seed);
_validateOnChange(isPolyseed: isPolyseed);
},
onLanguageChange: (_) {
if (walletRestoreViewModel.hasBlockchainHeightLanguageSelector) {
final hasHeight = walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey
.currentState!.restoreHeightController.text.isNotEmpty;
if (hasHeight) {
walletRestoreViewModel.isButtonEnabled = _isValidSeed();
}
} else {
walletRestoreViewModel.isButtonEnabled = _isValidSeed();
}
onLanguageChange: (String language) {
final isPolyseed = language.startsWith("POLYSEED_");
_validateOnChange(isPolyseed: isPolyseed);
}));
break;
case WalletRestoreMode.keys:
@@ -104,6 +93,7 @@ class WalletRestorePage extends BasePage {
));
final WalletRestoreViewModel walletRestoreViewModel;
final SeedTypeViewModel seedTypeViewModel;
final PageController _controller;
final List<Widget> _pages;
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
@@ -163,7 +153,8 @@ class WalletRestorePage extends BasePage {
color: Theme.of(context).colorScheme.background,
child: Center(
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint),
constraints:
BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@@ -219,10 +210,10 @@ class WalletRestorePage extends BasePage {
const SizedBox(height: 25),
GestureDetector(
onTap: () {
Navigator.of(context)
.pushNamed(Routes.advancedPrivacySettings, arguments: walletRestoreViewModel.type);
Navigator.of(context).pushNamed(Routes.advancedPrivacySettings,
arguments: walletRestoreViewModel.type);
},
child: Text(S.of(context).advanced_privacy_settings),
child: Text(S.of(context).advanced_settings),
),
],
),
@@ -235,9 +226,26 @@ class WalletRestorePage extends BasePage {
);
}
void _validateOnChange({bool isPolyseed = false}) {
if (!isPolyseed && walletRestoreViewModel.hasBlockchainHeightLanguageSelector) {
final hasHeight = walletRestoreFromSeedFormKey
.currentState?.blockchainHeightKey.currentState?.restoreHeightController.text.isNotEmpty;
if (hasHeight == true) {
walletRestoreViewModel.isButtonEnabled = _isValidSeed();
}
} else {
walletRestoreViewModel.isButtonEnabled = _isValidSeed();
}
}
bool _isValidSeed() {
final seedWords =
walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.text.split(' ');
final seedPhrase =
walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.text;
if (walletRestoreViewModel.type == WalletType.monero && Polyseed.isValidSeed(seedPhrase))
return true;
final seedWords = seedPhrase.split(' ');
if ((walletRestoreViewModel.type == WalletType.monero ||
walletRestoreViewModel.type == WalletType.haven) &&
@@ -282,7 +290,8 @@ class WalletRestorePage extends BasePage {
if (walletRestoreViewModel.hasBlockchainHeightLanguageSelector) {
credentials['height'] =
walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey.currentState!.height;
walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey.currentState?.height ??
-1;
}
credentials['name'] =
+4 -4
View File
@@ -2,9 +2,9 @@ import 'dart:async';
import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/core/totp_request_details.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
@@ -169,7 +169,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
);
launchUri = null;
} else if (isWalletConnectLink) {
if (widget.appStore.wallet!.type == WalletType.ethereum) {
if (isEVMCompatibleChain(widget.appStore.wallet!.type)) {
widget.navigatorKey.currentState?.pushNamed(
Routes.walletConnectConnectionsListing,
arguments: launchUri,
@@ -179,7 +179,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
_nonETHWalletErrorToast(S.current.switchToETHWallet);
}
}
launchUri = null;
return WillPopScope(
onWillPop: () async => false,
@@ -205,7 +205,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
String? _getRouteToGo() {
if (isWalletConnectLink) {
if (widget.appStore.wallet!.type != WalletType.ethereum) {
if (isEVMCompatibleChain(widget.appStore.wallet!.type)) {
_nonETHWalletErrorToast(S.current.switchToETHWallet);
return null;
}
@@ -1,95 +0,0 @@
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/src/widgets/seed_language_selector.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart';
class SeedLanguage extends BasePage {
SeedLanguage({required this.onConfirm});
final Function(BuildContext, String) onConfirm;
final walletNameImage = Image.asset('assets/images/wallet_name.png');
final walletNameLightImage =
Image.asset('assets/images/wallet_name_light.png');
@override
String get title => S.current.wallet_list_restore_wallet;
@override
Widget body(BuildContext context) =>
SeedLanguageForm(
onConfirm: onConfirm,
walletImage: currentTheme.type == ThemeType.dark
? walletNameImage : walletNameLightImage);
}
class SeedLanguageForm extends StatefulWidget {
SeedLanguageForm({required this.onConfirm, required this.walletImage});
final Function(BuildContext, String) onConfirm;
final Image walletImage;
@override
SeedLanguageFormState createState() => SeedLanguageFormState();
}
class SeedLanguageFormState extends State<SeedLanguageForm> {
static const aspectRatioImage = 1.22;
final _languageSelectorKey = GlobalKey<SeedLanguageSelectorState>();
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 24),
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
content:
Column(crossAxisAlignment: CrossAxisAlignment.center, children: [
Padding(
padding: EdgeInsets.only(left: 12, right: 12),
child: AspectRatio(
aspectRatio: aspectRatioImage,
child: FittedBox(child: widget.walletImage,
fit: BoxFit.fill)),
),
Padding(
padding: EdgeInsets.only(top: 40),
child: Text(
S.of(context).seed_language_choose,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.w500,
color:
Theme.of(context).extension<CakeTextTheme>()!.titleColor),
),
),
Padding(
padding: EdgeInsets.only(top: 24),
child: SeedLanguageSelector(
key: _languageSelectorKey,
initialSelected: defaultSeedLanguage),
)
]),
bottomSectionPadding:
EdgeInsets.only(left: 24, right: 24, bottom: 24),
bottomSection: Observer(
builder: (context) {
return PrimaryButton(
onPressed: () => widget.onConfirm(
context, _languageSelectorKey.currentState!.selected),
text: S.of(context).seed_language_next,
color: Colors.green,
textColor: Colors.white);
},
)),
);
}
}
@@ -1,82 +0,0 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/generated/i18n.dart';
List<Image> flagImages = [
Image.asset('assets/images/flags/usa.png'),
Image.asset('assets/images/flags/chn.png'),
Image.asset('assets/images/flags/nld.png'),
Image.asset('assets/images/flags/deu.png'),
Image.asset('assets/images/flags/jpn.png'),
Image.asset('assets/images/flags/prt.png'),
Image.asset('assets/images/flags/rus.png'),
Image.asset('assets/images/flags/esp.png'),
Image.asset('assets/images/flags/fra.png'),
Image.asset('assets/images/flags/ita.png'),
];
const List<String> languageCodes = [
'Eng',
'Chi',
'Ned',
'Ger',
'Jap',
'Por',
'Rus',
'Esp',
'Fre',
'Ita',
];
const defaultSeedLanguage = 'English';
const List<String> seedLanguages = [
defaultSeedLanguage,
'Chinese (simplified)',
'Dutch',
'German',
'Japanese',
'Portuguese',
'Russian',
'Spanish',
'French',
'Italian',
];
enum Places { topLeft, topRight, bottomLeft, bottomRight, inside }
class SeedLanguagePicker extends StatefulWidget {
SeedLanguagePicker({Key? key, this.selected = defaultSeedLanguage, required this.onItemSelected})
: super(key: key);
final String selected;
final Function(String) onItemSelected;
@override
SeedLanguagePickerState createState() =>
SeedLanguagePickerState(selected: selected, onItemSelected: onItemSelected);
}
class SeedLanguagePickerState extends State<SeedLanguagePicker> {
SeedLanguagePickerState({required this.selected, required this.onItemSelected});
final String selected;
final Function(String) onItemSelected;
@override
Widget build(BuildContext context) {
return Picker(
selectedAtIndex: seedLanguages.indexOf(selected),
items: seedLanguages,
images: flagImages,
isGridView: true,
title: S.of(context).seed_choose,
hintText: S.of(context).seed_choose,
matchingCriteria: (String language, String searchText) {
return language.toLowerCase().contains(searchText);
},
onItemSelected: onItemSelected,
);
}
}
@@ -1,4 +1,5 @@
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
@@ -8,7 +9,6 @@ import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
@@ -85,7 +85,7 @@ class ConnectionSyncPage extends BasePage {
);
},
),
if (dashboardViewModel.wallet.type == WalletType.ethereum) ...[
if (isEVMCompatibleChain(dashboardViewModel.wallet.type)) ...[
WalletConnectTile(
onTap: () => Navigator.of(context).pushNamed(Routes.walletConnectConnectionsListing),
),
@@ -101,6 +101,7 @@ class ConnectionSyncPage extends BasePage {
);
}
Future<void> _presentReconnectAlert(BuildContext context) async {
await showPopUp<void>(
context: context,
@@ -1,5 +1,3 @@
import 'package:cake_wallet/buy/buy_provider.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/routes.dart';
@@ -42,9 +40,10 @@ class OtherSettingsPage extends BasePage {
handler: (BuildContext context) =>
Navigator.of(context).pushNamed(Routes.changeRep),
),
if(_otherSettingsViewModel.isEnabledBuyAction)
SettingsPickerCell(
title: S.current.default_buy_provider,
items: BuyProviderType.values,
items: _otherSettingsViewModel.availableBuyProviders,
displayItem: _otherSettingsViewModel.getBuyProviderType,
selectedItem: _otherSettingsViewModel.buyProviderType,
onItemSelected: _otherSettingsViewModel.onBuyProviderTypeSelected,
@@ -87,6 +87,14 @@ class PrivacyPage extends BasePage {
onValueChange: (BuildContext _, bool value) {
_privacySettingsViewModel.setUseEtherscan(value);
}),
if (_privacySettingsViewModel.canUsePolygonScan)
SettingsSwitcherCell(
title: S.current.polygonscan_history,
value: _privacySettingsViewModel.usePolygonScan,
onValueChange: (BuildContext _, bool value) {
_privacySettingsViewModel.setUsePolygonScan(value);
},
),
SettingsCellWithArrow(
title: S.current.domain_looks_up,
handler: (context) => Navigator.of(context).pushNamed(Routes.domainLookupsPage),
+33 -33
View File
@@ -4,7 +4,7 @@ import 'dart:io';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:flutter/material.dart';
import 'package:tor/tor.dart';
// import 'package:tor/tor.dart';
class TorPage extends BasePage {
final AppStore appStore;
@@ -40,44 +40,44 @@ class _TorPageBodyState extends State<TorPageBody> {
connecting = true; // Update flag
});
await Tor.init();
// Start the proxy
await Tor.instance.start();
// Toggle started flag.
setState(() {
torEnabled = Tor.instance.enabled; // Update flag
connecting = false;
});
final node = widget.appStore.settingsStore.getCurrentNode(widget.appStore.wallet!.type);
if (node.socksProxyAddress?.isEmpty ?? true) {
node.socksProxyAddress = "${InternetAddress.loopbackIPv4.address}:${Tor.instance.port}";
}
widget.appStore.wallet!.connectToNode(node: node);
// await Tor.init();
//
// // Start the proxy
// await Tor.instance.start();
//
// // Toggle started flag.
// setState(() {
// torEnabled = Tor.instance.enabled; // Update flag
// connecting = false;
// });
//
// final node = widget.appStore.settingsStore.getCurrentNode(widget.appStore.wallet!.type);
// if (node.socksProxyAddress?.isEmpty ?? true) {
// node.socksProxyAddress = "${InternetAddress.loopbackIPv4.address}:${Tor.instance.port}";
// }
// widget.appStore.wallet!.connectToNode(node: node);
print('Done awaiting; tor should be running');
}
Future<void> endTor() async {
// Start the proxy
Tor.instance.disable();
// Toggle started flag.
setState(() {
torEnabled = Tor.instance.enabled; // Update flag
});
print('Done awaiting; tor should be stopped');
}
@override
void initState() {
super.initState();
torEnabled = Tor.instance.enabled;
// // Start the proxy
// Tor.instance.disable();
//
// // Toggle started flag.
// setState(() {
// torEnabled = Tor.instance.enabled; // Update flag
// });
//
// print('Done awaiting; tor should be stopped');
}
//
// @override
// void initState() {
// super.initState();
//
// torEnabled = Tor.instance.enabled;
// }
@override
void dispose() {
@@ -57,6 +57,8 @@ class ChatwootWidgetState extends State<ChatwootWidget> {
return true;
}
Future<void> storeCookie(String value) async =>
await widget.secureStorage.write(key: COOKIE_KEY, value: value);
Future<void> storeCookie(String value) async {
await widget.secureStorage.delete(key: COOKIE_KEY);
await widget.secureStorage.write(key: COOKIE_KEY, value: value);
}
}
@@ -31,6 +31,8 @@ class WalletConnectConnectionsView extends StatelessWidget {
final actualLinkList = launchUri.query.split("uri=");
if (actualLinkList.length <= 1) return;
final query = actualLinkList[1];
final uri = Uri.decodeComponent(query);
@@ -14,12 +14,14 @@ import 'connection_widget.dart';
class ConnectionRequestWidget extends StatefulWidget {
const ConnectionRequestWidget({
required this.wallet,
required this.chaindIdNamespace,
this.authRequest,
this.sessionProposal,
Key? key,
}) : super(key: key);
final Web3Wallet wallet;
final String chaindIdNamespace;
final AuthRequestModel? authRequest;
final SessionRequestModel? sessionProposal;
@@ -52,23 +54,26 @@ class _ConnectionRequestWidgetState extends State<ConnectionRequestWidget> {
return _ConnectionMetadataDisplayWidget(
metadata: metadata,
wallet: widget.wallet,
authRequest: widget.authRequest,
sessionProposal: widget.sessionProposal,
wallet: widget.wallet,
chaindIdNamespace: widget.chaindIdNamespace,
);
}
}
class _ConnectionMetadataDisplayWidget extends StatelessWidget {
const _ConnectionMetadataDisplayWidget({
required this.metadata,
required this.wallet,
this.authRequest,
required this.metadata,
required this.sessionProposal,
required this.chaindIdNamespace,
this.authRequest,
});
final ConnectionMetadata? metadata;
final Web3Wallet wallet;
final String chaindIdNamespace;
final AuthRequestModel? authRequest;
final SessionRequestModel? sessionProposal;
@@ -114,7 +119,11 @@ class _ConnectionMetadataDisplayWidget extends StatelessWidget {
const SizedBox(height: 8),
Visibility(
visible: authRequest != null,
child: _AuthRequestWidget(wallet: wallet, authRequest: authRequest),
child: _AuthRequestWidget(
wallet: wallet,
authRequest: authRequest,
chaindIdNamespace: chaindIdNamespace,
),
//If authRequest is null, sessionProposal is not null.
replacement: _SessionProposalWidget(sessionProposal: sessionProposal!),
@@ -126,16 +135,21 @@ class _ConnectionMetadataDisplayWidget extends StatelessWidget {
}
class _AuthRequestWidget extends StatelessWidget {
const _AuthRequestWidget({required this.wallet, this.authRequest});
const _AuthRequestWidget({
required this.wallet,
required this.chaindIdNamespace,
this.authRequest,
});
final Web3Wallet wallet;
final String chaindIdNamespace;
final AuthRequestModel? authRequest;
@override
Widget build(BuildContext context) {
final model = ConnectionModel(
text: wallet.formatAuthMessage(
iss: 'did:pkh:eip155:1:${authRequest!.iss}',
iss: 'did:pkh:$chaindIdNamespace:${authRequest!.iss}',
cacaoPayload: CacaoRequestPayload.fromPayloadParams(
authRequest!.request.payloadParams,
),
@@ -49,6 +49,7 @@ class WalletListBodyState extends State<WalletListBody> {
final ethereumIcon = Image.asset('assets/images/eth_icon.png', height: 24, width: 24);
final bitcoinCashIcon = Image.asset('assets/images/bch_icon.png', height: 24, width: 24);
final nanoIcon = Image.asset('assets/images/nano_icon.png', height: 24, width: 24);
final polygonIcon = Image.asset('assets/images/matic_icon.png', height: 24, width: 24);
final scrollController = ScrollController();
final double tileHeight = 60;
Flushbar<void>? _progressBar;
@@ -256,6 +257,8 @@ class WalletListBodyState extends State<WalletListBody> {
return bitcoinCashIcon;
case WalletType.nano:
return nanoIcon;
case WalletType.polygon:
return polygonIcon;
default:
return nonWalletTypeIcon;
}
+93
View File
@@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/entities/seed_type.dart';
class SeedLanguagePickerOption {
SeedLanguagePickerOption(this.name, this.nameLocalized, this.image, this.supportedSeedTypes);
final String name;
final String nameLocalized;
final Image image;
final List<SeedType> supportedSeedTypes;
}
final List<SeedLanguagePickerOption> seedLanguages = [
SeedLanguagePickerOption('English', S.current.seed_language_english,
Image.asset('assets/images/flags/usa.png'), [SeedType.legacy, SeedType.polyseed]),
SeedLanguagePickerOption('Chinese (simplified)', S.current.seed_language_chinese,
Image.asset('assets/images/flags/chn.png'), [SeedType.legacy, SeedType.polyseed]),
SeedLanguagePickerOption('Chinese (Traditional)', S.current.seed_language_chinese_traditional,
Image.asset('assets/images/flags/chn.png'), [SeedType.polyseed]),
SeedLanguagePickerOption('Dutch', S.current.seed_language_dutch,
Image.asset('assets/images/flags/nld.png'), [SeedType.legacy]),
SeedLanguagePickerOption('German', S.current.seed_language_german,
Image.asset('assets/images/flags/deu.png'), [SeedType.legacy]),
SeedLanguagePickerOption('Japanese', S.current.seed_language_japanese,
Image.asset('assets/images/flags/jpn.png'), [SeedType.legacy, SeedType.polyseed]),
SeedLanguagePickerOption('Korean', S.current.seed_language_korean,
Image.asset('assets/images/flags/kor.png'), [SeedType.polyseed]),
SeedLanguagePickerOption('Portuguese', S.current.seed_language_portuguese,
Image.asset('assets/images/flags/prt.png'), [SeedType.legacy, SeedType.polyseed]),
SeedLanguagePickerOption('Russian', S.current.seed_language_russian,
Image.asset('assets/images/flags/rus.png'), [SeedType.legacy]),
SeedLanguagePickerOption('Czech', S.current.seed_language_czech,
Image.asset('assets/images/flags/czk.png'), [SeedType.polyseed]),
SeedLanguagePickerOption('Spanish', S.current.seed_language_spanish,
Image.asset('assets/images/flags/esp.png'), [SeedType.legacy, SeedType.polyseed]),
SeedLanguagePickerOption('French', S.current.seed_language_french,
Image.asset('assets/images/flags/fra.png'), [SeedType.legacy, SeedType.polyseed]),
SeedLanguagePickerOption('Italian', S.current.seed_language_italian,
Image.asset('assets/images/flags/ita.png'), [SeedType.legacy, SeedType.polyseed]),
];
const defaultSeedLanguage = 'English';
enum Places { topLeft, topRight, bottomLeft, bottomRight, inside }
class SeedLanguagePicker extends StatefulWidget {
SeedLanguagePicker(
{Key? key,
this.selected = defaultSeedLanguage,
this.seedType = SeedType.defaultSeedType,
required this.onItemSelected})
: super(key: key);
final SeedType seedType;
final String selected;
final Function(String) onItemSelected;
@override
SeedLanguagePickerState createState() => SeedLanguagePickerState(
selected: selected, onItemSelected: onItemSelected, seedType: seedType);
}
class SeedLanguagePickerState extends State<SeedLanguagePicker> {
SeedLanguagePickerState(
{required this.selected, required this.onItemSelected, required this.seedType});
final SeedType seedType;
final String selected;
final Function(String) onItemSelected;
@override
Widget build(BuildContext context) {
final availableSeedLanguages = seedLanguages
.where((SeedLanguagePickerOption e) => e.supportedSeedTypes.contains(seedType));
return Picker(
selectedAtIndex: availableSeedLanguages.map((e) => e.name).toList().indexOf(selected),
items: availableSeedLanguages.map((e) => e.name).toList(),
images: availableSeedLanguages.map((e) => e.image).toList(),
isGridView: true,
title: S.of(context).seed_choose,
hintText: S.of(context).seed_choose,
matchingCriteria: (String language, String searchText) {
return language.toLowerCase().contains(searchText);
},
onItemSelected: onItemSelected,
);
}
}
+17 -24
View File
@@ -1,49 +1,42 @@
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/entities/seed_type.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart';
import 'package:cake_wallet/src/widgets/seed_language_picker.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
class SeedLanguageSelector extends StatefulWidget {
SeedLanguageSelector({Key? key, required this.initialSelected})
SeedLanguageSelector(
{Key? key, required this.initialSelected, this.seedType = SeedType.defaultSeedType})
: super(key: key);
final String initialSelected;
final SeedType seedType;
@override
SeedLanguageSelectorState createState() =>
SeedLanguageSelectorState(selected: initialSelected);
SeedLanguageSelectorState createState() => SeedLanguageSelectorState(selected: initialSelected);
}
class SeedLanguageSelectorState extends State<SeedLanguageSelector> {
SeedLanguageSelectorState({required this.selected});
final seedLocales = [
S.current.seed_language_english,
S.current.seed_language_chinese,
S.current.seed_language_dutch,
S.current.seed_language_german,
S.current.seed_language_japanese,
S.current.seed_language_portuguese,
S.current.seed_language_russian,
S.current.seed_language_spanish,
S.current.seed_language_french,
S.current.seed_language_italian,
];
String selected;
@override
Widget build(BuildContext context) {
return SelectButton(
image: null,
text: seedLocales[seedLanguages.indexOf(selected)],
text:
"${seedLanguages.firstWhere((e) => e.name == selected).nameLocalized} (${S.of(context).seed_language})",
onTap: () async {
await showPopUp<String>(
context: context,
builder: (_) => SeedLanguagePicker(
selected: this.selected,
onItemSelected: (String selected) =>
setState(() => this.selected = selected)));
context: context,
builder: (_) => SeedLanguagePicker(
selected: this.selected,
seedType: widget.seedType,
onItemSelected: (String selected) => setState(() => this.selected = selected),
),
);
},
);
}
+2 -2
View File
@@ -1,8 +1,8 @@
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_core/balance.dart';
import 'package:cw_core/wallet_base.dart';
@@ -44,7 +44,7 @@ abstract class AppStoreBase with Store {
this.wallet = wallet;
this.wallet!.setExceptionHandler(ExceptionHandler.onError);
if (wallet.type == WalletType.ethereum) {
if (isEVMCompatibleChain(wallet.type)) {
getIt.get<Web3WalletService>().init();
}
}
+177 -95
View File
@@ -10,7 +10,9 @@ import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/pin_code_required_duration.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/entities/seed_phrase_length.dart';
import 'package:cake_wallet/entities/seed_type.dart';
import 'package:cake_wallet/entities/sort_balance_types.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
import 'package:cake_wallet/utils/device_info.dart';
@@ -34,7 +36,6 @@ import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/entities/action_list_display_mode.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cw_core/set_app_secure_native.dart';
part 'settings_store.g.dart';
class SettingsStore = SettingsStoreBase with _$SettingsStore;
@@ -48,6 +49,7 @@ abstract class SettingsStoreBase with Store {
required BalanceDisplayMode initialBalanceDisplayMode,
required bool initialSaveRecipientAddress,
required AutoGenerateSubaddressStatus initialAutoGenerateSubaddressStatus,
required SeedType initialMoneroSeedType,
required bool initialAppSecure,
required bool initialDisableBuy,
required bool initialDisableSell,
@@ -86,6 +88,7 @@ abstract class SettingsStoreBase with Store {
required this.sortBalanceBy,
required this.pinNativeTokenAtTop,
required this.useEtherscan,
required this.usePolygonScan,
required this.defaultNanoRep,
required this.defaultBananoRep,
required this.lookupsTwitter,
@@ -99,6 +102,7 @@ abstract class SettingsStoreBase with Store {
TransactionPriority? initialHavenTransactionPriority,
TransactionPriority? initialLitecoinTransactionPriority,
TransactionPriority? initialEthereumTransactionPriority,
TransactionPriority? initialPolygonTransactionPriority,
TransactionPriority? initialBitcoinCashTransactionPriority})
: nodes = ObservableMap<WalletType, Node>.of(nodes),
powNodes = ObservableMap<WalletType, Node>.of(powNodes),
@@ -108,6 +112,7 @@ abstract class SettingsStoreBase with Store {
balanceDisplayMode = initialBalanceDisplayMode,
shouldSaveRecipientAddress = initialSaveRecipientAddress,
autoGenerateSubaddressStatus = initialAutoGenerateSubaddressStatus,
moneroSeedType = initialMoneroSeedType,
fiatApiMode = initialFiatMode,
allowBiometricalAuthentication = initialAllowBiometricalAuthentication,
selectedCake2FAPreset = initialCake2FAPresetOptions,
@@ -117,7 +122,6 @@ abstract class SettingsStoreBase with Store {
isAppSecure = initialAppSecure,
disableBuy = initialDisableBuy,
disableSell = initialDisableSell,
defaultBuyProvider = initialDefaultBuyProvider,
shouldShowMarketPlaceInDashboard = initialShouldShowMarketPlaceInDashboard,
exchangeStatus = initialExchangeStatus,
currentTheme = initialTheme,
@@ -162,12 +166,22 @@ abstract class SettingsStoreBase with Store {
priority[WalletType.ethereum] = initialEthereumTransactionPriority;
}
if (initialPolygonTransactionPriority != null) {
priority[WalletType.polygon] = initialPolygonTransactionPriority;
}
if (initialBitcoinCashTransactionPriority != null) {
priority[WalletType.bitcoinCash] = initialBitcoinCashTransactionPriority;
}
initializeTrocadorProviderStates();
WalletType.values.forEach((walletType) {
final key = 'defaultBuyProvider_${walletType.toString()}';
final providerIndex = sharedPreferences.getInt(key);
defaultBuyProviders[walletType] = providerIndex != null ? BuyProviderType.values[providerIndex] : BuyProviderType.AskEachTime;
});
reaction(
(_) => fiatCurrency,
(FiatCurrency fiatCurrency) => sharedPreferences.setString(
@@ -199,6 +213,9 @@ abstract class SettingsStoreBase with Store {
case WalletType.bitcoinCash:
key = PreferencesKey.bitcoinCashTransactionPriority;
break;
case WalletType.polygon:
key = PreferencesKey.polygonTransactionPriority;
break;
default:
key = null;
}
@@ -231,15 +248,25 @@ abstract class SettingsStoreBase with Store {
sharedPreferences.setBool(PreferencesKey.disableSellKey, disableSell));
reaction(
(_) => defaultBuyProvider,
(BuyProviderType defaultBuyProvider) =>
sharedPreferences.setInt(PreferencesKey.defaultBuyProvider, defaultBuyProvider.index));
(_) => defaultBuyProviders.asObservable(),
(ObservableMap<WalletType, BuyProviderType> providers) {
providers.forEach((walletType, provider) {
final key = 'defaultBuyProvider_${walletType.toString()}';
sharedPreferences.setInt(key, provider.index);
});
}
);
reaction(
(_) => autoGenerateSubaddressStatus,
(AutoGenerateSubaddressStatus autoGenerateSubaddressStatus) => sharedPreferences.setInt(
PreferencesKey.autoGenerateSubaddressStatusKey, autoGenerateSubaddressStatus.value));
reaction(
(_) => moneroSeedType,
(SeedType moneroSeedType) =>
sharedPreferences.setInt(PreferencesKey.moneroSeedType, moneroSeedType.raw));
reaction(
(_) => fiatApiMode,
(FiatApiMode mode) =>
@@ -315,6 +342,7 @@ abstract class SettingsStoreBase with Store {
reaction((_) => totpSecretKey,
(String totpKey) => sharedPreferences.setString(PreferencesKey.totpSecretKey, totpKey));
reaction(
(_) => numberOfFailedTokenTrials,
(int failedTokenTrail) =>
@@ -334,9 +362,9 @@ abstract class SettingsStoreBase with Store {
sharedPreferences.setString(PreferencesKey.currentLanguageCode, languageCode));
reaction(
(_) => seedPhraseLength,
(SeedPhraseLength seedPhraseWordCount) =>
sharedPreferences.setInt(PreferencesKey.currentSeedPhraseLength, seedPhraseWordCount.value));
(_) => seedPhraseLength,
(SeedPhraseLength seedPhraseWordCount) => sharedPreferences.setInt(
PreferencesKey.currentSeedPhraseLength, seedPhraseWordCount.value));
reaction(
(_) => pinTimeOutDuration,
@@ -380,6 +408,11 @@ abstract class SettingsStoreBase with Store {
(bool useEtherscan) =>
_sharedPreferences.setBool(PreferencesKey.useEtherscan, useEtherscan));
reaction(
(_) => usePolygonScan,
(bool usePolygonScan) =>
_sharedPreferences.setBool(PreferencesKey.usePolygonScan, usePolygonScan));
reaction((_) => defaultNanoRep,
(String nanoRep) => _sharedPreferences.setString(PreferencesKey.defaultNanoRep, nanoRep));
@@ -388,34 +421,32 @@ abstract class SettingsStoreBase with Store {
(String bananoRep) =>
_sharedPreferences.setString(PreferencesKey.defaultBananoRep, bananoRep));
reaction(
(_) => lookupsTwitter,
(bool looksUpTwitter) =>
(_) => lookupsTwitter,
(bool looksUpTwitter) =>
_sharedPreferences.setBool(PreferencesKey.lookupsTwitter, looksUpTwitter));
reaction(
(_) => lookupsMastodon,
(bool looksUpMastodon) =>
(_) => lookupsMastodon,
(bool looksUpMastodon) =>
_sharedPreferences.setBool(PreferencesKey.lookupsMastodon, looksUpMastodon));
reaction(
(_) => lookupsYatService,
(bool looksUpYatService) =>
(_) => lookupsYatService,
(bool looksUpYatService) =>
_sharedPreferences.setBool(PreferencesKey.lookupsYatService, looksUpYatService));
reaction(
(_) => lookupsUnstoppableDomains,
(bool looksUpUnstoppableDomains) =>
_sharedPreferences.setBool(PreferencesKey.lookupsUnstoppableDomains, looksUpUnstoppableDomains));
(_) => lookupsUnstoppableDomains,
(bool looksUpUnstoppableDomains) => _sharedPreferences.setBool(
PreferencesKey.lookupsUnstoppableDomains, looksUpUnstoppableDomains));
reaction(
(_) => lookupsOpenAlias,
(bool looksUpOpenAlias) =>
(_) => lookupsOpenAlias,
(bool looksUpOpenAlias) =>
_sharedPreferences.setBool(PreferencesKey.lookupsOpenAlias, looksUpOpenAlias));
reaction(
(_) => lookupsENS,
(bool looksUpENS) =>
_sharedPreferences.setBool(PreferencesKey.lookupsENS, looksUpENS));
reaction((_) => lookupsENS,
(bool looksUpENS) => _sharedPreferences.setBool(PreferencesKey.lookupsENS, looksUpENS));
this.nodes.observe((change) {
if (change.newValue != null && change.key != null) {
@@ -435,6 +466,7 @@ abstract class SettingsStoreBase with Store {
static const defaultPinCodeTimeOutDuration = PinCodeRequiredDuration.tenminutes;
static const defaultAutoGenerateSubaddressStatus = AutoGenerateSubaddressStatus.initialized;
static const defaultSeedPhraseLength = SeedPhraseLength.twelveWords;
static const defaultMoneroSeedType = SeedType.defaultSeedType;
@observable
FiatCurrency fiatCurrency;
@@ -460,6 +492,9 @@ abstract class SettingsStoreBase with Store {
@observable
AutoGenerateSubaddressStatus autoGenerateSubaddressStatus;
@observable
SeedType moneroSeedType;
@observable
bool isAppSecure;
@@ -469,9 +504,6 @@ abstract class SettingsStoreBase with Store {
@observable
bool disableSell;
@observable
BuyProviderType defaultBuyProvider;
@observable
bool allowBiometricalAuthentication;
@@ -541,6 +573,9 @@ abstract class SettingsStoreBase with Store {
@observable
ObservableMap<String, bool> trocadorProviderStates = ObservableMap<String, bool>();
@observable
ObservableMap<WalletType, BuyProviderType> defaultBuyProviders = ObservableMap<WalletType, BuyProviderType>();
@observable
SortBalanceBy sortBalanceBy;
@@ -550,6 +585,9 @@ abstract class SettingsStoreBase with Store {
@observable
bool useEtherscan;
@observable
bool usePolygonScan;
@observable
String defaultNanoRep;
@@ -639,6 +677,7 @@ abstract class SettingsStoreBase with Store {
TransactionPriority? havenTransactionPriority;
TransactionPriority? litecoinTransactionPriority;
TransactionPriority? ethereumTransactionPriority;
TransactionPriority? polygonTransactionPriority;
TransactionPriority? bitcoinCashTransactionPriority;
if (sharedPreferences.getInt(PreferencesKey.havenTransactionPriority) != null) {
@@ -650,9 +689,13 @@ abstract class SettingsStoreBase with Store {
sharedPreferences.getInt(PreferencesKey.litecoinTransactionPriority)!);
}
if (sharedPreferences.getInt(PreferencesKey.ethereumTransactionPriority) != null) {
ethereumTransactionPriority = bitcoin?.deserializeLitecoinTransactionPriority(
ethereumTransactionPriority = ethereum?.deserializeEthereumTransactionPriority(
sharedPreferences.getInt(PreferencesKey.ethereumTransactionPriority)!);
}
if (sharedPreferences.getInt(PreferencesKey.polygonTransactionPriority) != null) {
polygonTransactionPriority = polygon?.deserializePolygonTransactionPriority(
sharedPreferences.getInt(PreferencesKey.polygonTransactionPriority)!);
}
if (sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority) != null) {
bitcoinCashTransactionPriority = bitcoinCash?.deserializeBitcoinCashTransactionPriority(
sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority)!);
@@ -664,6 +707,7 @@ abstract class SettingsStoreBase with Store {
litecoinTransactionPriority ??= bitcoin?.getLitecoinTransactionPriorityMedium();
ethereumTransactionPriority ??= ethereum?.getDefaultTransactionPriority();
bitcoinCashTransactionPriority ??= bitcoinCash?.getDefaultTransactionPriority();
polygonTransactionPriority ??= polygon?.getDefaultTransactionPriority();
final currentBalanceDisplayMode = BalanceDisplayMode.deserialize(
raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
@@ -737,12 +781,14 @@ abstract class SettingsStoreBase with Store {
final pinNativeTokenAtTop =
sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop) ?? true;
final useEtherscan = sharedPreferences.getBool(PreferencesKey.useEtherscan) ?? true;
final usePolygonScan = sharedPreferences.getBool(PreferencesKey.usePolygonScan) ?? true;
final defaultNanoRep = sharedPreferences.getString(PreferencesKey.defaultNanoRep) ?? "";
final defaultBananoRep = sharedPreferences.getString(PreferencesKey.defaultBananoRep) ?? "";
final lookupsTwitter = sharedPreferences.getBool(PreferencesKey.lookupsTwitter) ?? true;
final lookupsMastodon = sharedPreferences.getBool(PreferencesKey.lookupsMastodon) ?? true;
final lookupsYatService = sharedPreferences.getBool(PreferencesKey.lookupsYatService) ?? true;
final lookupsUnstoppableDomains = sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true;
final lookupsUnstoppableDomains =
sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true;
final lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
final lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
@@ -762,6 +808,7 @@ abstract class SettingsStoreBase with Store {
sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
final ethereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
final polygonNodeId = sharedPreferences.getInt(PreferencesKey.currentPolygonNodeIdKey);
final nanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
final nanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoPowNodeIdKey);
final moneroNode = nodeSource.get(nodeId);
@@ -769,18 +816,27 @@ abstract class SettingsStoreBase with Store {
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
final havenNode = nodeSource.get(havenNodeId);
final ethereumNode = nodeSource.get(ethereumNodeId);
final polygonNode = nodeSource.get(polygonNodeId);
final bitcoinCashElectrumServer = nodeSource.get(bitcoinCashElectrumServerId);
final nanoNode = nodeSource.get(nanoNodeId);
final nanoPowNode = powNodeSource.get(nanoPowNodeId);
final packageInfo = await PackageInfo.fromPlatform();
final deviceName = await _getDeviceName() ?? '';
final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true;
final generateSubaddresses =
sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey);
final autoGenerateSubaddressStatus = generateSubaddresses != null
? AutoGenerateSubaddressStatus.deserialize(raw: generateSubaddresses)
: defaultAutoGenerateSubaddressStatus;
final _moneroSeedType = sharedPreferences.getInt(PreferencesKey.moneroSeedType);
final moneroSeedType = _moneroSeedType != null
? SeedType.deserialize(raw: _moneroSeedType)
: defaultMoneroSeedType;
final nodes = <WalletType, Node>{};
final powNodes = <WalletType, Node>{};
@@ -804,6 +860,10 @@ abstract class SettingsStoreBase with Store {
nodes[WalletType.ethereum] = ethereumNode;
}
if (polygonNode != null) {
nodes[WalletType.polygon] = polygonNode;
}
if (bitcoinCashElectrumServer != null) {
nodes[WalletType.bitcoinCash] = bitcoinCashElectrumServer;
}
@@ -817,74 +877,77 @@ abstract class SettingsStoreBase with Store {
}
final savedSyncMode = SyncMode.all.firstWhere((element) {
return element.type.index == (sharedPreferences.getInt(PreferencesKey.syncModeKey) ?? 1);
return element.type.index == (sharedPreferences.getInt(PreferencesKey.syncModeKey) ?? 0);
});
final savedSyncAll = sharedPreferences.getBool(PreferencesKey.syncAllKey) ?? true;
return SettingsStore(
sharedPreferences: sharedPreferences,
initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard,
nodes: nodes,
powNodes: powNodes,
appVersion: packageInfo.version,
deviceName: deviceName,
isBitcoinBuyEnabled: isBitcoinBuyEnabled,
initialFiatCurrency: currentFiatCurrency,
initialBalanceDisplayMode: currentBalanceDisplayMode,
initialSaveRecipientAddress: shouldSaveRecipientAddress,
initialAutoGenerateSubaddressStatus: autoGenerateSubaddressStatus,
initialAppSecure: isAppSecure,
initialDisableBuy: disableBuy,
initialDisableSell: disableSell,
initialDefaultBuyProvider: defaultBuyProvider,
initialFiatMode: currentFiatApiMode,
initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
initialCake2FAPresetOptions: selectedCake2FAPreset,
initialUseTOTP2FA: useTOTP2FA,
initialTotpSecretKey: totpSecretKey,
initialFailedTokenTrial: tokenTrialNumber,
initialExchangeStatus: exchangeStatus,
initialTheme: savedTheme,
actionlistDisplayMode: actionListDisplayMode,
initialPinLength: pinLength,
pinTimeOutDuration: pinCodeTimeOutDuration,
seedPhraseLength: seedPhraseWordCount,
initialLanguageCode: savedLanguageCode,
sortBalanceBy: sortBalanceBy,
pinNativeTokenAtTop: pinNativeTokenAtTop,
useEtherscan: useEtherscan,
defaultNanoRep: defaultNanoRep,
defaultBananoRep: defaultBananoRep,
lookupsTwitter: lookupsTwitter,
lookupsMastodon: lookupsMastodon,
lookupsYatService: lookupsYatService,
lookupsUnstoppableDomains: lookupsUnstoppableDomains,
lookupsOpenAlias: lookupsOpenAlias,
lookupsENS: lookupsENS,
initialMoneroTransactionPriority: moneroTransactionPriority,
initialBitcoinTransactionPriority: bitcoinTransactionPriority,
initialHavenTransactionPriority: havenTransactionPriority,
initialLitecoinTransactionPriority: litecoinTransactionPriority,
initialBitcoinCashTransactionPriority: bitcoinCashTransactionPriority,
initialShouldRequireTOTP2FAForAccessingWallet: shouldRequireTOTP2FAForAccessingWallet,
initialShouldRequireTOTP2FAForSendsToContact: shouldRequireTOTP2FAForSendsToContact,
initialShouldRequireTOTP2FAForSendsToNonContact: shouldRequireTOTP2FAForSendsToNonContact,
initialShouldRequireTOTP2FAForSendsToInternalWallets:
shouldRequireTOTP2FAForSendsToInternalWallets,
initialShouldRequireTOTP2FAForExchangesToInternalWallets:
shouldRequireTOTP2FAForExchangesToInternalWallets,
return SettingsStore(
sharedPreferences: sharedPreferences,
initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard,
nodes: nodes,
powNodes: powNodes,
appVersion: packageInfo.version,
deviceName: deviceName,
isBitcoinBuyEnabled: isBitcoinBuyEnabled,
initialFiatCurrency: currentFiatCurrency,
initialBalanceDisplayMode: currentBalanceDisplayMode,
initialSaveRecipientAddress: shouldSaveRecipientAddress,
initialAutoGenerateSubaddressStatus: autoGenerateSubaddressStatus,
initialMoneroSeedType: moneroSeedType,
initialAppSecure: isAppSecure,
initialDisableBuy: disableBuy,
initialDisableSell: disableSell,
initialDefaultBuyProvider: defaultBuyProvider,
initialFiatMode: currentFiatApiMode,
initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
initialCake2FAPresetOptions: selectedCake2FAPreset,
initialUseTOTP2FA: useTOTP2FA,
initialTotpSecretKey: totpSecretKey,
initialFailedTokenTrial: tokenTrialNumber,
initialExchangeStatus: exchangeStatus,
initialTheme: savedTheme,
actionlistDisplayMode: actionListDisplayMode,
initialPinLength: pinLength,
pinTimeOutDuration: pinCodeTimeOutDuration,
seedPhraseLength: seedPhraseWordCount,
initialLanguageCode: savedLanguageCode,
sortBalanceBy: sortBalanceBy,
pinNativeTokenAtTop: pinNativeTokenAtTop,
useEtherscan: useEtherscan,
usePolygonScan: usePolygonScan,
defaultNanoRep: defaultNanoRep,
defaultBananoRep: defaultBananoRep,
lookupsTwitter: lookupsTwitter,
lookupsMastodon: lookupsMastodon,
lookupsYatService: lookupsYatService,
lookupsUnstoppableDomains: lookupsUnstoppableDomains,
lookupsOpenAlias: lookupsOpenAlias,
lookupsENS: lookupsENS,
initialMoneroTransactionPriority: moneroTransactionPriority,
initialBitcoinTransactionPriority: bitcoinTransactionPriority,
initialHavenTransactionPriority: havenTransactionPriority,
initialLitecoinTransactionPriority: litecoinTransactionPriority,
initialBitcoinCashTransactionPriority: bitcoinCashTransactionPriority,
initialShouldRequireTOTP2FAForAccessingWallet: shouldRequireTOTP2FAForAccessingWallet,
initialShouldRequireTOTP2FAForSendsToContact: shouldRequireTOTP2FAForSendsToContact,
initialShouldRequireTOTP2FAForSendsToNonContact: shouldRequireTOTP2FAForSendsToNonContact,
initialShouldRequireTOTP2FAForSendsToInternalWallets:
shouldRequireTOTP2FAForSendsToInternalWallets,
initialShouldRequireTOTP2FAForExchangesToInternalWallets:
shouldRequireTOTP2FAForExchangesToInternalWallets,
initialShouldRequireTOTP2FAForExchangesToExternalWallets:
shouldRequireTOTP2FAForExchangesToExternalWallets,
initialShouldRequireTOTP2FAForAddingContacts: shouldRequireTOTP2FAForAddingContacts,
initialShouldRequireTOTP2FAForCreatingNewWallets: shouldRequireTOTP2FAForCreatingNewWallets,
initialShouldRequireTOTP2FAForAllSecurityAndBackupSettings:
shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
initialEthereumTransactionPriority: ethereumTransactionPriority,
backgroundTasks: backgroundTasks,
initialSyncMode: savedSyncMode,
initialSyncAll: savedSyncAll,
shouldShowYatPopup: shouldShowYatPopup);
}
initialShouldRequireTOTP2FAForAddingContacts: shouldRequireTOTP2FAForAddingContacts,
initialShouldRequireTOTP2FAForCreatingNewWallets: shouldRequireTOTP2FAForCreatingNewWallets,
initialShouldRequireTOTP2FAForAllSecurityAndBackupSettings:
shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
initialEthereumTransactionPriority: ethereumTransactionPriority,
initialPolygonTransactionPriority: polygonTransactionPriority,
backgroundTasks: backgroundTasks,
initialSyncMode: savedSyncMode,
initialSyncAll: savedSyncAll,
shouldShowYatPopup: shouldShowYatPopup);
}
Future<void> reload({required Box<Node> nodeSource}) async {
final sharedPreferences = await getIt.getAsync<SharedPreferences>();
@@ -914,6 +977,11 @@ abstract class SettingsStoreBase with Store {
sharedPreferences.getInt(PreferencesKey.ethereumTransactionPriority)!) ??
priority[WalletType.ethereum]!;
}
if (sharedPreferences.getInt(PreferencesKey.polygonTransactionPriority) != null) {
priority[WalletType.polygon] = polygon?.deserializePolygonTransactionPriority(
sharedPreferences.getInt(PreferencesKey.polygonTransactionPriority)!) ??
priority[WalletType.polygon]!;
}
if (sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority) != null) {
priority[WalletType.bitcoinCash] = bitcoinCash?.deserializeBitcoinCashTransactionPriority(
sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority)!) ??
@@ -927,6 +995,12 @@ abstract class SettingsStoreBase with Store {
? AutoGenerateSubaddressStatus.deserialize(raw: generateSubaddresses)
: defaultAutoGenerateSubaddressStatus;
final _moneroSeedType = sharedPreferences.getInt(PreferencesKey.moneroSeedType);
moneroSeedType = _moneroSeedType != null
? SeedType.deserialize(raw: _moneroSeedType)
: defaultMoneroSeedType;
balanceDisplayMode = BalanceDisplayMode.deserialize(
raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
shouldSaveRecipientAddress =
@@ -939,8 +1013,6 @@ abstract class SettingsStoreBase with Store {
isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure;
disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? disableBuy;
disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? disableSell;
defaultBuyProvider =
BuyProviderType.values[sharedPreferences.getInt(PreferencesKey.defaultBuyProvider) ?? 0];
allowBiometricalAuthentication =
sharedPreferences.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
allowBiometricalAuthentication;
@@ -1001,12 +1073,14 @@ abstract class SettingsStoreBase with Store {
.values[sharedPreferences.getInt(PreferencesKey.sortBalanceBy) ?? sortBalanceBy.index];
pinNativeTokenAtTop = sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop) ?? true;
useEtherscan = sharedPreferences.getBool(PreferencesKey.useEtherscan) ?? true;
usePolygonScan = sharedPreferences.getBool(PreferencesKey.usePolygonScan) ?? true;
defaultNanoRep = sharedPreferences.getString(PreferencesKey.defaultNanoRep) ?? "";
defaultBananoRep = sharedPreferences.getString(PreferencesKey.defaultBananoRep) ?? "";
lookupsTwitter = sharedPreferences.getBool(PreferencesKey.lookupsTwitter) ?? true;
lookupsMastodon = sharedPreferences.getBool(PreferencesKey.lookupsMastodon) ?? true;
lookupsYatService = sharedPreferences.getBool(PreferencesKey.lookupsYatService) ?? true;
lookupsUnstoppableDomains = sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true;
lookupsUnstoppableDomains =
sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true;
lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
@@ -1019,6 +1093,7 @@ abstract class SettingsStoreBase with Store {
sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
final ethereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
final polygonNodeId = sharedPreferences.getInt(PreferencesKey.currentPolygonNodeIdKey);
final nanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
final nanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
final moneroNode = nodeSource.get(nodeId);
@@ -1026,6 +1101,7 @@ abstract class SettingsStoreBase with Store {
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
final havenNode = nodeSource.get(havenNodeId);
final ethereumNode = nodeSource.get(ethereumNodeId);
final polygonNode = nodeSource.get(polygonNodeId);
final bitcoinCashNode = nodeSource.get(bitcoinCashElectrumServerId);
final nanoNode = nodeSource.get(nanoNodeId);
@@ -1049,6 +1125,10 @@ abstract class SettingsStoreBase with Store {
nodes[WalletType.ethereum] = ethereumNode;
}
if (polygonNode != null) {
nodes[WalletType.polygon] = polygonNode;
}
if (bitcoinCashNode != null) {
nodes[WalletType.bitcoinCash] = bitcoinCashNode;
}
@@ -1084,6 +1164,9 @@ abstract class SettingsStoreBase with Store {
case WalletType.nano:
await _sharedPreferences.setInt(PreferencesKey.currentNanoNodeIdKey, node.key as int);
break;
case WalletType.polygon:
await _sharedPreferences.setInt(PreferencesKey.currentPolygonNodeIdKey, node.key as int);
break;
default:
break;
}
@@ -1115,7 +1198,6 @@ abstract class SettingsStoreBase with Store {
trocadorProviderStates[providerName] = state;
}
static Future<String?> _getDeviceName() async {
String? deviceName = '';
final deviceInfoPlugin = DeviceInfoPlugin();
@@ -29,6 +29,8 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
bool get hasSeedPhraseLengthOption =>
type == WalletType.bitcoinCash || type == WalletType.ethereum;
bool get hasSeedTypeOption => type == WalletType.monero;
@computed
bool get addCustomNode => _addCustomNode;
@@ -1,5 +1,6 @@
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/sort_balance_types.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/balance.dart';
@@ -81,7 +82,7 @@ abstract class BalanceViewModelBase with Store {
bool get isFiatDisabled => settingsStore.fiatApiMode == FiatApiMode.disabled;
@computed
bool get isHomeScreenSettingsEnabled => wallet.type == WalletType.ethereum;
bool get isHomeScreenSettingsEnabled => isEVMCompatibleChain(wallet.type);
@computed
bool get hasAccounts => wallet.type == WalletType.monero;
@@ -123,6 +124,7 @@ abstract class BalanceViewModelBase with Store {
case WalletType.monero:
case WalletType.haven:
case WalletType.ethereum:
case WalletType.polygon:
return S.current.xmr_available_balance;
default:
return S.current.confirmed;
@@ -135,6 +137,7 @@ abstract class BalanceViewModelBase with Store {
case WalletType.monero:
case WalletType.haven:
case WalletType.ethereum:
case WalletType.polygon:
return S.current.xmr_full_balance;
default:
return S.current.unconfirmed;
@@ -272,7 +275,8 @@ abstract class BalanceViewModelBase with Store {
}
@computed
bool get hasAdditionalBalance => wallet.type != WalletType.ethereum;
bool get hasAdditionalBalance => !isEVMCompatibleChain(wallet.type);
@computed
List<BalanceRecord> get formattedBalances {
@@ -282,10 +282,14 @@ abstract class DashboardViewModelBase with Store {
Map<String, List<FilterItem>> filterItems;
BuyProviderType get defaultBuyProvider => settingsStore.defaultBuyProvider;
BuyProviderType get defaultBuyProvider =>
settingsStore.defaultBuyProviders[wallet.type] ??
BuyProviderType.AskEachTime;
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
List<BuyProviderType> get availableProviders => BuyProviderType.getAvailableProviders(wallet.type);
bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup;
@action
@@ -2,10 +2,12 @@ import 'package:cake_wallet/core/fiat_conversion_service.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/sort_balance_types.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/erc20_token.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart';
part 'home_settings_view_model.g.dart';
@@ -42,18 +44,41 @@ abstract class HomeSettingsViewModelBase with Store {
void setPinNativeToken(bool value) => _settingsStore.pinNativeTokenAtTop = value;
Future<void> addErc20Token(Erc20Token token) async {
await ethereum!.addErc20Token(_balanceViewModel.wallet, token);
if (_balanceViewModel.wallet.type == WalletType.ethereum) {
await ethereum!.addErc20Token(_balanceViewModel.wallet, token);
}
if (_balanceViewModel.wallet.type == WalletType.polygon) {
await polygon!.addErc20Token(_balanceViewModel.wallet, token);
}
_updateTokensList();
_updateFiatPrices(token);
}
Future<void> deleteErc20Token(Erc20Token token) async {
await ethereum!.deleteErc20Token(_balanceViewModel.wallet, token);
if (_balanceViewModel.wallet.type == WalletType.ethereum) {
await ethereum!.deleteErc20Token(_balanceViewModel.wallet, token);
}
if (_balanceViewModel.wallet.type == WalletType.polygon) {
await polygon!.deleteErc20Token(_balanceViewModel.wallet, token);
}
_updateTokensList();
}
Future<Erc20Token?> getErc20Token(String contractAddress) async =>
await ethereum!.getErc20Token(_balanceViewModel.wallet, contractAddress);
Future<Erc20Token?> getErc20Token(String contractAddress) async {
if (_balanceViewModel.wallet.type == WalletType.ethereum) {
return await ethereum!.getErc20Token(_balanceViewModel.wallet, contractAddress);
}
if (_balanceViewModel.wallet.type == WalletType.polygon) {
return await polygon!.getErc20Token(_balanceViewModel.wallet, contractAddress);
}
return null;
}
CryptoCurrency get nativeToken => _balanceViewModel.wallet.currency;
@@ -69,7 +94,12 @@ abstract class HomeSettingsViewModelBase with Store {
void changeTokenAvailability(Erc20Token token, bool value) async {
token.enabled = value;
ethereum!.addErc20Token(_balanceViewModel.wallet, token);
if (_balanceViewModel.wallet.type == WalletType.ethereum) {
ethereum!.addErc20Token(_balanceViewModel.wallet, token);
}
if (_balanceViewModel.wallet.type == WalletType.polygon) {
polygon!.addErc20Token(_balanceViewModel.wallet, token);
}
_refreshTokensList();
}
@@ -83,7 +113,8 @@ abstract class HomeSettingsViewModelBase with Store {
return -1;
} else if (e2.enabled && !e1.enabled) {
return 1;
} else if (!e1.enabled && !e2.enabled) { // if both are disabled then sort alphabetically
} else if (!e1.enabled && !e2.enabled) {
// if both are disabled then sort alphabetically
return e1.name.compareTo(e2.name);
}
@@ -92,11 +123,21 @@ abstract class HomeSettingsViewModelBase with Store {
tokens.clear();
tokens.addAll(ethereum!
.getERC20Currencies(_balanceViewModel.wallet)
.where((element) => _matchesSearchText(element))
.toList()
..sort(_sortFunc));
if (_balanceViewModel.wallet.type == WalletType.ethereum) {
tokens.addAll(ethereum!
.getERC20Currencies(_balanceViewModel.wallet)
.where((element) => _matchesSearchText(element))
.toList()
..sort(_sortFunc));
}
if (_balanceViewModel.wallet.type == WalletType.polygon) {
tokens.addAll(polygon!
.getERC20Currencies(_balanceViewModel.wallet)
.where((element) => _matchesSearchText(element))
.toList()
..sort(_sortFunc));
}
}
@action
+9 -4
View File
@@ -1,8 +1,8 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
import 'dart:developer';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
import 'package:http/http.dart' as http;
import 'package:mobx/mobx.dart';
@@ -38,21 +38,26 @@ abstract class NFTViewModelBase with Store {
@action
Future<void> getNFTAssetByWallet() async {
if (!isEVMCompatibleChain(appStore.wallet!.type)) return;
final walletAddress = appStore.wallet!.walletInfo.address;
log('Fetching wallet NFTs for $walletAddress');
final chainName = getChainNameBasedOnWalletType(appStore.wallet!.type);
// the [chain] refers to the chain network that the nft is on
// the [format] refers to the number format type of the responses
// the [normalizedMetadata] field is a boolean that determines if
// the response would include a json string of the NFT Metadata that can be decoded
// and used within the wallet
// the [excludeSpam] field is a boolean that determines if spam nfts be excluded from the response.
final uri = Uri.https(
'deep-index.moralis.io',
'/api/v2.2/$walletAddress/nft',
{
"chain": "eth",
"chain": chainName,
"format": "decimal",
"media_items": "false",
"exclude_spam": "true",
"normalizeMetadata": "true",
},
);
@@ -91,7 +96,7 @@ abstract class NFTViewModelBase with Store {
@action
Future<void> importNFT(String tokenAddress, String tokenId) async {
final chainName = getChainNameBasedOnWalletType(appStore.wallet!.type);
// the [chain] refers to the chain network that the nft is on
// the [format] refers to the number format type of the responses
// the [normalizedMetadata] field is a boolean that determines if
@@ -101,7 +106,7 @@ abstract class NFTViewModelBase with Store {
'deep-index.moralis.io',
'/api/v2.2/nft/$tokenAddress/$tokenId',
{
"chain": "eth",
"chain": chainName,
"format": "decimal",
"media_items": "false",
"normalizeMetadata": "true",
@@ -3,6 +3,7 @@ import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cake_wallet/store/settings_store.dart';
@@ -91,6 +92,13 @@ class TransactionListItem extends ActionListItem with Keyable {
cryptoAmount: ethereum!.formatterEthereumAmountToDouble(transaction: transaction),
price: price);
break;
case WalletType.polygon:
final asset = polygon!.assetOfTransaction(balanceViewModel.wallet, transaction);
final price = balanceViewModel.fiatConvertationStore.prices[asset];
amount = calculateFiatAmountRaw(
cryptoAmount: polygon!.formatterPolygonAmountToDouble(transaction: transaction),
price: price);
break;
case WalletType.nano:
amount = calculateFiatAmountRaw(
cryptoAmount: double.parse(nanoUtil!.getRawAsDecimalString(
@@ -37,6 +37,7 @@ abstract class EditBackupPasswordViewModelBase with Store {
@action
Future<void> save() async {
final key = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
await secureStorage.delete(key: key);
await secureStorage.write(key: key, value: backupPassword);
secretStore.write(key: key, value: backupPassword);
}
@@ -28,10 +28,7 @@ abstract class ExchangeTradeViewModelBase with Store {
required this.tradesStore,
required this.sendViewModel})
: trade = tradesStore.trade!,
isSendable = tradesStore.trade!.from == wallet.currency ||
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto ||
(wallet.currency == CryptoCurrency.eth &&
tradesStore.trade!.from.tag == CryptoCurrency.eth.title),
isSendable = _checkIfCanSend(tradesStore, wallet),
items = ObservableList<ExchangeTradeItem>() {
switch (trade.provider) {
case ExchangeProviderDescription.changeNow:
@@ -155,4 +152,19 @@ abstract class ExchangeTradeViewModelBase with Store {
isCopied: true),
]);
}
static bool _checkIfCanSend(TradesStore tradesStore, WalletBase wallet) {
bool _isEthToken() =>
wallet.currency == CryptoCurrency.eth &&
tradesStore.trade!.from.tag == CryptoCurrency.eth.title;
bool _isPolygonToken() =>
wallet.currency == CryptoCurrency.maticpoly &&
tradesStore.trade!.from.tag == CryptoCurrency.maticpoly.tag;
return tradesStore.trade!.from == wallet.currency ||
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto ||
_isEthToken() ||
_isPolygonToken();
}
}
@@ -23,6 +23,7 @@ import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/dashboard/trades_store.dart';
import 'package:cake_wallet/store/settings_store.dart';
@@ -287,6 +288,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
return transactionPriority == ethereum!.getEthereumTransactionPrioritySlow();
case WalletType.bitcoinCash:
return transactionPriority == bitcoinCash!.getBitcoinCashTransactionPrioritySlow();
case WalletType.polygon:
return transactionPriority == polygon!.getPolygonTransactionPrioritySlow();
default:
return false;
}
@@ -626,6 +629,10 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
depositCurrency = CryptoCurrency.nano;
receiveCurrency = CryptoCurrency.xmr;
break;
case WalletType.polygon:
depositCurrency = CryptoCurrency.maticpoly;
receiveCurrency = CryptoCurrency.xmr;
break;
default:
break;
}
@@ -713,6 +720,9 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
case WalletType.bitcoinCash:
_settingsStore.priority[wallet.type] = bitcoinCash!.getDefaultTransactionPriority();
break;
case WalletType.polygon:
_settingsStore.priority[wallet.type] = polygon!.getDefaultTransactionPriority();
break;
default:
break;
}
@@ -72,6 +72,9 @@ abstract class NodeListViewModelBase with Store {
case WalletType.nano:
node = getNanoDefaultNode(nodes: _nodeSource)!;
break;
case WalletType.polygon:
node = getPolygonDefaultNode(nodes: _nodeSource)!;
break;
default:
throw Exception('Unexpected wallet type: ${_appStore.wallet!.type}');
}
@@ -2,6 +2,7 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
import 'package:hive/hive.dart';
@@ -71,6 +72,9 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
case WalletType.ethereum:
return ethereum!.createEthereumRestoreWalletFromPrivateKey(
name: name, password: password, privateKey: restoreWallet.privateKey!);
case WalletType.polygon:
return polygon!.createPolygonRestoreWalletFromPrivateKey(
name: name, password: password, privateKey: restoreWallet.privateKey!);
default:
throw Exception('Unexpected type: ${restoreWallet.type.toString()}');
}
@@ -95,6 +99,9 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
case WalletType.nano:
return nano!.createNanoRestoreWalletFromSeedCredentials(
name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
case WalletType.polygon:
return polygon!.createPolygonRestoreWalletFromSeedCredentials(
name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
default:
throw Exception('Unexpected type: ${type.toString()}');
}
+1 -1
View File
@@ -45,7 +45,7 @@ class RestoredWallet {
factory RestoredWallet.fromSeed(Map<String, dynamic> json) {
final height = json['height'] as String?;
final mnemonic_seed = json['mnemonic_seed'] as String?;
final seed = json['seed'] as String?;
final seed = json['seed'] as String? ?? json['hexSeed'] as String?;
return RestoredWallet(
restoreMode: json['mode'] as WalletRestoreMode,
type: json['type'] as WalletType,
@@ -10,6 +10,7 @@ import 'package:cw_core/wallet_type.dart';
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:collection/collection.dart';
import 'package:polyseed/polyseed.dart';
class WalletRestoreFromQRCode {
WalletRestoreFromQRCode();
@@ -25,6 +26,7 @@ class WalletRestoreFromQRCode {
'litecoin-wallet': WalletType.litecoin,
'litecoin_wallet': WalletType.litecoin,
'ethereum-wallet': WalletType.ethereum,
'polygon-wallet': WalletType.polygon,
'nano-wallet': WalletType.nano,
'nano_wallet': WalletType.nano,
'bitcoincash': WalletType.bitcoinCash,
@@ -51,7 +53,7 @@ class WalletRestoreFromQRCode {
RegExp _getPattern(int wordCount) =>
RegExp(r'(?<=\W|^)((?:\w+\s+){' + (wordCount - 1).toString() + r'}\w+)(?=\W|$)');
List<int> patternCounts = walletType == WalletType.monero ? [25, 14, 13] : [24, 18, 12];
List<int> patternCounts = walletType == WalletType.monero ? [25, 16, 14, 13] : [24, 18, 12];
for (final count in patternCounts) {
final pattern = _getPattern(count);
@@ -123,12 +125,17 @@ class WalletRestoreFromQRCode {
}
if (credentials['seed'] != null) {
final seedValue = credentials['seed'];
final seedValue = credentials['seed'] as String;
final words = SeedValidator.getWordList(type: type, language: 'english');
if (type == WalletType.monero && Polyseed.isValidSeed(seedValue)) {
return WalletRestoreMode.seed;
}
seedValue.split(' ').forEach((element) {
if (!words.contains(element)) {
throw Exception(
'Unexpected restore mode: mnemonic_seed is invalid or does\'t match wallet type');
"Unexpected restore mode: mnemonic_seed is invalid or doesn't match wallet type");
}
});
return WalletRestoreMode.seed;
@@ -151,6 +158,23 @@ class WalletRestoreFromQRCode {
return WalletRestoreMode.keys;
}
if (type == WalletType.polygon && credentials.containsKey('private_key')) {
final privateKey = credentials['private_key'] as String;
if (privateKey.isEmpty) {
throw Exception('Unexpected restore mode: private_key');
}
return WalletRestoreMode.keys;
}
if ((type == WalletType.nano || type == WalletType.banano) &&
credentials.containsKey('hexSeed')) {
final hexSeed = credentials['hexSeed'] as String;
if (hexSeed.isEmpty) {
throw Exception('Unexpected restore mode: hexSeed');
}
return WalletRestoreMode.seed;
}
throw Exception('Unexpected restore mode: restore params are invalid');
}
}
+19
View File
@@ -0,0 +1,19 @@
import 'package:cake_wallet/entities/seed_type.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:mobx/mobx.dart';
part 'seed_type_view_model.g.dart';
class SeedTypeViewModel = SeedTypeViewModelBase with _$SeedTypeViewModel;
abstract class SeedTypeViewModelBase with Store {
SeedTypeViewModelBase(this._appStore);
@computed
SeedType get moneroSeedType => _appStore.settingsStore.moneroSeedType;
@action
void setMoneroSeedType(SeedType seedType) => _appStore.settingsStore.moneroSeedType = seedType;
final AppStore _appStore;
}
+18 -8
View File
@@ -4,6 +4,8 @@ import 'package:cake_wallet/entities/parse_address_from_domain.dart';
import 'package:cake_wallet/entities/parsed_address.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/haven/haven.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/src/screens/send/widgets/extract_address_from_parsed.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:flutter/material.dart';
@@ -27,7 +29,8 @@ const String cryptoNumberPattern = '0.0';
class Output = OutputBase with _$Output;
abstract class OutputBase with Store {
OutputBase(this._wallet, this._settingsStore, this._fiatConversationStore, this.cryptoCurrencyHandler)
OutputBase(
this._wallet, this._settingsStore, this._fiatConversationStore, this.cryptoCurrencyHandler)
: _cryptoNumberFormat = NumberFormat(cryptoNumberPattern),
key = UniqueKey(),
sendAll = false,
@@ -65,8 +68,7 @@ abstract class OutputBase with Store {
@computed
bool get isParsedAddress =>
parsedAddress.parseFrom != ParseFrom.notParsed &&
parsedAddress.name.isNotEmpty;
parsedAddress.parseFrom != ParseFrom.notParsed && parsedAddress.name.isNotEmpty;
@computed
int get formattedCryptoAmount {
@@ -83,8 +85,7 @@ abstract class OutputBase with Store {
case WalletType.bitcoin:
case WalletType.litecoin:
case WalletType.bitcoinCash:
_amount =
bitcoin!.formatterStringDoubleToBitcoinAmount(_cryptoAmount);
_amount = bitcoin!.formatterStringDoubleToBitcoinAmount(_cryptoAmount);
break;
case WalletType.haven:
_amount = haven!.formatterMoneroParseAmount(amount: _cryptoAmount);
@@ -92,6 +93,9 @@ abstract class OutputBase with Store {
case WalletType.ethereum:
_amount = ethereum!.formatterEthereumParseAmount(_cryptoAmount);
break;
case WalletType.polygon:
_amount = polygon!.formatterPolygonParseAmount(_cryptoAmount);
break;
default:
break;
}
@@ -130,6 +134,10 @@ abstract class OutputBase with Store {
if (_wallet.type == WalletType.ethereum) {
return ethereum!.formatterEthereumAmountToDouble(amount: BigInt.from(fee));
}
if (_wallet.type == WalletType.polygon) {
return polygon!.formatterPolygonAmountToDouble(amount: BigInt.from(fee));
}
} catch (e) {
print(e.toString());
}
@@ -140,10 +148,11 @@ abstract class OutputBase with Store {
@computed
String get estimatedFeeFiatAmount {
try {
final currency = _wallet.type == WalletType.ethereum ? _wallet.currency : cryptoCurrencyHandler();
final currency = isEVMCompatibleChain(_wallet.type)
? _wallet.currency
: cryptoCurrencyHandler();
final fiat = calculateFiatAmountRaw(
price: _fiatConversationStore.prices[currency]!,
cryptoAmount: estimatedFee);
price: _fiatConversationStore.prices[currency]!, cryptoAmount: estimatedFee);
return fiat;
} catch (_) {
return '0.00';
@@ -240,6 +249,7 @@ abstract class OutputBase with Store {
maximumFractionDigits = 12;
break;
case WalletType.ethereum:
case WalletType.polygon:
maximumFractionDigits = 12;
break;
default:
@@ -50,7 +50,9 @@ abstract class SendTemplateViewModelBase with Store {
TemplateValidator get templateValidator => TemplateValidator();
bool get hasMultiRecipient =>
_wallet.type != WalletType.haven && _wallet.type != WalletType.ethereum;
_wallet.type != WalletType.haven &&
_wallet.type != WalletType.ethereum &&
_wallet.type != WalletType.polygon;
@computed
CryptoCurrency get cryptoCurrency => _wallet.currency;
+13 -4
View File
@@ -5,6 +5,8 @@ import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
import 'package:cake_wallet/entities/contact_record.dart';
import 'package:cake_wallet/entities/wallet_contact.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
@@ -42,7 +44,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
void onWalletChange(wallet) {
currencies = wallet.balance.keys.toList();
selectedCryptoCurrency = wallet.currency;
hasMultipleTokens = wallet.type == WalletType.ethereum;
hasMultipleTokens = isEVMCompatibleChain(wallet.type);
}
SendViewModelBase(
@@ -55,7 +57,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
) : state = InitialExecutionState(),
currencies = appStore.wallet!.balance.keys.toList(),
selectedCryptoCurrency = appStore.wallet!.currency,
hasMultipleTokens = appStore.wallet!.type == WalletType.ethereum,
hasMultipleTokens = isEVMCompatibleChain(appStore.wallet!.type),
outputs = ObservableList<Output>(),
_settingsStore = appStore.settingsStore,
fiatFromSettings = appStore.settingsStore.fiatCurrency,
@@ -119,7 +121,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
try {
if (pendingTransaction != null) {
final currency =
walletType == WalletType.ethereum ? wallet.currency : selectedCryptoCurrency;
isEVMCompatibleChain(walletType) ? wallet.currency : selectedCryptoCurrency;
final fiat = calculateFiatAmount(
price: _fiatConversationStore.prices[currency]!,
cryptoAmount: pendingTransaction!.feeFormatted);
@@ -372,6 +374,9 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
priority: priority!, currency: selectedCryptoCurrency);
case WalletType.nano:
return nano!.createNanoTransactionCredentials(outputs);
case WalletType.polygon:
return polygon!.createPolygonTransactionCredentials(outputs,
priority: priority!, currency: selectedCryptoCurrency);
default:
throw Exception('Unexpected wallet type: ${wallet.type}');
}
@@ -412,11 +417,15 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
WalletType walletType,
CryptoCurrency currency,
) {
if (walletType == WalletType.ethereum || walletType == WalletType.haven) {
if (walletType == WalletType.ethereum ||
walletType == WalletType.polygon ||
walletType == WalletType.haven) {
if (error.contains('gas required exceeds allowance') ||
error.contains('insufficient funds for')) {
return S.current.do_not_have_enough_gas_asset(currency.toString());
}
return error;
}
return error;
@@ -13,14 +13,15 @@ import 'package:package_info/package_info.dart';
part 'other_settings_view_model.g.dart';
class OtherSettingsViewModel = OtherSettingsViewModelBase with _$OtherSettingsViewModel;
class OtherSettingsViewModel = OtherSettingsViewModelBase
with _$OtherSettingsViewModel;
abstract class OtherSettingsViewModelBase with Store {
OtherSettingsViewModelBase(this._settingsStore, this._wallet)
: walletType = _wallet.type,
currentVersion = '' {
PackageInfo.fromPlatform()
.then((PackageInfo packageInfo) => currentVersion = packageInfo.version);
PackageInfo.fromPlatform().then(
(PackageInfo packageInfo) => currentVersion = packageInfo.version);
final priority = _settingsStore.priority[_wallet.type];
final priorities = priorityForWalletType(_wallet.type);
@@ -31,7 +32,8 @@ abstract class OtherSettingsViewModelBase with Store {
}
final WalletType walletType;
final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> _wallet;
final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
TransactionInfo> _wallet;
@observable
String currentVersion;
@@ -50,15 +52,19 @@ abstract class OtherSettingsViewModelBase with Store {
}
@computed
bool get changeRepresentativeEnabled {
if (_wallet.type == WalletType.nano || _wallet.type == WalletType.banano) {
return true;
}
bool get changeRepresentativeEnabled =>
_wallet.type == WalletType.nano || _wallet.type == WalletType.banano;
return false;
}
BuyProviderType get buyProviderType { return _settingsStore.defaultBuyProvider; }
@computed
bool get isEnabledBuyAction =>
!_settingsStore.disableBuy && _wallet.type != WalletType.haven;
List<BuyProviderType> get availableBuyProviders =>
BuyProviderType.getAvailableProviders(walletType);
BuyProviderType get buyProviderType =>
_settingsStore.defaultBuyProviders[walletType] ??
BuyProviderType.AskEachTime;
String getDisplayPriority(dynamic priority) {
final _priority = priority as TransactionPriority;
@@ -73,7 +79,7 @@ abstract class OtherSettingsViewModelBase with Store {
return priority.toString();
}
String getBuyProviderType (dynamic buyProviderType) {
String getBuyProviderType(dynamic buyProviderType) {
final _buyProviderType = buyProviderType as BuyProviderType;
return _buyProviderType.toString();
@@ -83,6 +89,5 @@ abstract class OtherSettingsViewModelBase with Store {
_settingsStore.priority[_wallet.type] = priority;
void onBuyProviderTypeSelected(BuyProviderType buyProviderType) =>
_settingsStore.defaultBuyProvider = buyProviderType;
_settingsStore.defaultBuyProviders[walletType] = buyProviderType;
}
@@ -1,6 +1,7 @@
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cw_core/balance.dart';
import 'package:cw_core/transaction_history.dart';
@@ -12,8 +13,7 @@ import 'package:cake_wallet/entities/fiat_api_mode.dart';
part 'privacy_settings_view_model.g.dart';
class
PrivacySettingsViewModel = PrivacySettingsViewModelBase with _$PrivacySettingsViewModel;
class PrivacySettingsViewModel = PrivacySettingsViewModelBase with _$PrivacySettingsViewModel;
abstract class PrivacySettingsViewModelBase with Store {
PrivacySettingsViewModelBase(this._settingsStore, this._wallet);
@@ -58,6 +58,9 @@ abstract class PrivacySettingsViewModelBase with Store {
@computed
bool get useEtherscan => _settingsStore.useEtherscan;
@computed
bool get usePolygonScan => _settingsStore.usePolygonScan;
@computed
bool get lookupTwitter => _settingsStore.lookupsTwitter;
@@ -78,6 +81,8 @@ abstract class PrivacySettingsViewModelBase with Store {
bool get canUseEtherscan => _wallet.type == WalletType.ethereum;
bool get canUsePolygonScan => _wallet.type == WalletType.polygon;
@action
void setShouldSaveRecipientAddress(bool value) =>
_settingsStore.shouldSaveRecipientAddress = value;
@@ -120,4 +125,10 @@ abstract class PrivacySettingsViewModelBase with Store {
_settingsStore.useEtherscan = value;
ethereum!.updateEtherscanUsageState(_wallet, value);
}
@action
void setUsePolygonScan(bool value) {
_settingsStore.usePolygonScan = value;
polygon!.updatePolygonScanUsageState(_wallet, value);
}
}
@@ -51,6 +51,9 @@ abstract class TransactionDetailsViewModelBase with Store {
case WalletType.nano:
_addNanoListItems(tx, dateFormat);
break;
case WalletType.polygon:
_addPolygonListItems(tx, dateFormat);
break;
default:
break;
}
@@ -125,7 +128,9 @@ abstract class TransactionDetailsViewModelBase with Store {
case WalletType.nano:
return 'https://nanolooker.com/block/${txId}';
case WalletType.banano:
return 'https://bananolooker.com/block/${txId}';
return 'https://bananolooker.com/block/${txId}';
case WalletType.polygon:
return 'https://polygonscan.com/tx/${txId}';
default:
return '';
}
@@ -148,6 +153,8 @@ abstract class TransactionDetailsViewModelBase with Store {
return S.current.view_transaction_on + 'nanolooker.com';
case WalletType.banano:
return S.current.view_transaction_on + 'bananolooker.com';
case WalletType.polygon:
return S.current.view_transaction_on + 'polygonscan.com';
default:
return '';
}
@@ -237,7 +244,6 @@ abstract class TransactionDetailsViewModelBase with Store {
items.addAll(_items);
}
void _addNanoListItems(TransactionInfo tx, DateFormat dateFormat) {
final _items = [
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
@@ -250,4 +256,21 @@ abstract class TransactionDetailsViewModelBase with Store {
items.addAll(_items);
}
void _addPolygonListItems(TransactionInfo tx, DateFormat dateFormat) {
final _items = [
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
StandartListItem(
title: S.current.transaction_details_date, value: dateFormat.format(tx.date)),
StandartListItem(title: S.current.confirmations, value: tx.confirmations.toString()),
StandartListItem(title: S.current.transaction_details_height, value: '${tx.height}'),
StandartListItem(title: S.current.transaction_details_amount, value: tx.amountFormatted()),
if (tx.feeFormatted()?.isNotEmpty ?? false)
StandartListItem(title: S.current.transaction_details_fee, value: tx.feeFormatted()!),
if (showRecipientAddress && tx.to != null)
StandartListItem(title: S.current.transaction_details_recipient_address, value: tx.to!),
];
items.addAll(_items);
}
}
@@ -1,6 +1,7 @@
import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
import 'package:cake_wallet/store/yat/yat_store.dart';
import 'package:cw_core/currency.dart';
@@ -139,6 +140,22 @@ class NanoURI extends PaymentURI {
}
}
class PolygonURI extends PaymentURI {
PolygonURI({required String amount, required String address})
: super(amount: amount, address: address);
@override
String toString() {
var base = 'polygon:' + address;
if (amount.isNotEmpty) {
base += '?amount=${amount.replaceAll(',', '.')}';
}
return base;
}
}
abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewModel with Store {
WalletAddressListViewModelBase({
required AppStore appStore,
@@ -216,6 +233,10 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
return NanoURI(amount: amount, address: address.address);
}
if (wallet.type == WalletType.polygon) {
return PolygonURI(amount: amount, address: address.address);
}
throw Exception('Unexpected type: ${type.toString()}');
}
@@ -272,6 +293,12 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
}
if (wallet.type == WalletType.polygon) {
final primaryAddress = polygon!.getAddress(wallet);
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
}
return addressList;
}
+48 -13
View File
@@ -1,3 +1,4 @@
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/transaction_info.dart';
@@ -9,6 +10,7 @@ import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.d
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/haven/haven.dart';
import 'package:cw_monero/api/wallet.dart' as monero_wallet;
import 'package:polyseed/polyseed.dart';
part 'wallet_keys_view_model.g.dart';
@@ -19,7 +21,8 @@ abstract class WalletKeysViewModelBase with Store {
: title = _appStore.wallet!.type == WalletType.bitcoin ||
_appStore.wallet!.type == WalletType.litecoin ||
_appStore.wallet!.type == WalletType.bitcoinCash ||
_appStore.wallet!.type == WalletType.ethereum
_appStore.wallet!.type == WalletType.ethereum ||
_appStore.wallet!.type == WalletType.polygon
? S.current.wallet_seed
: S.current.wallet_keys,
_restoreHeight = _appStore.wallet!.walletInfo.restoreHeight,
@@ -72,6 +75,15 @@ abstract class WalletKeysViewModelBase with Store {
StandartListItem(title: S.current.view_key_private, value: keys['privateViewKey']!),
StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
]);
if (_appStore.wallet?.seed != null && Polyseed.isValidSeed(_appStore.wallet!.seed!)) {
final lang = PolyseedLang.getByPhrase(_appStore.wallet!.seed!);
final legacyLang = _getLegacySeedLang(lang);
final legacySeed =
Polyseed.decode(_appStore.wallet!.seed!, lang, PolyseedCoin.POLYSEED_MONERO)
.toLegacySeed(legacyLang);
items.add(StandartListItem(title: S.current.wallet_seed_legacy, value: legacySeed));
}
}
if (_appStore.wallet!.type == WalletType.haven) {
@@ -98,7 +110,7 @@ abstract class WalletKeysViewModelBase with Store {
]);
}
if (_appStore.wallet!.type == WalletType.ethereum) {
if (isEVMCompatibleChain(_appStore.wallet!.type)) {
items.addAll([
if (_appStore.wallet!.privateKey != null)
StandartListItem(title: S.current.private_key, value: _appStore.wallet!.privateKey!),
@@ -107,19 +119,18 @@ abstract class WalletKeysViewModelBase with Store {
]);
}
if (_appStore.wallet!.type == WalletType.nano || _appStore.wallet!.type == WalletType.banano) {
bool nanoBased =
_appStore.wallet!.type == WalletType.nano || _appStore.wallet!.type == WalletType.banano;
// we don't necessarily have the seed phrase for nano / banano:
if (_appStore.wallet!.seed != null) {
items.addAll([
StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
]);
}
// we always have the hex version of the seed:
if (nanoBased) {
// we always have the hex version of the seed and private key:
items.addAll([
if (_appStore.wallet!.seed != null)
StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
if (_appStore.wallet!.hexSeed != null)
StandartListItem(title: S.current.seed_hex_form, value: _appStore.wallet!.hexSeed!),
if (_appStore.wallet!.privateKey != null)
StandartListItem(title: S.current.spend_key_private, value: _appStore.wallet!.privateKey!),
StandartListItem(title: S.current.private_key, value: _appStore.wallet!.privateKey!),
]);
}
}
@@ -152,6 +163,8 @@ abstract class WalletKeysViewModelBase with Store {
return 'nano-wallet';
case WalletType.banano:
return 'banano-wallet';
case WalletType.polygon:
return 'polygon-wallet';
default:
throw Exception('Unexpected wallet type: ${_appStore.wallet!.toString()}');
}
@@ -172,7 +185,10 @@ abstract class WalletKeysViewModelBase with Store {
final restoreHeightResult = await restoreHeight;
return {
if (_appStore.wallet!.seed != null) 'seed': _appStore.wallet!.seed!,
if (_appStore.wallet!.privateKey != null) 'private_key': _appStore.wallet!.privateKey!,
if (_appStore.wallet!.seed == null && _appStore.wallet!.hexSeed != null)
'hexSeed': _appStore.wallet!.hexSeed!,
if (_appStore.wallet!.seed == null && _appStore.wallet!.privateKey != null)
'private_key': _appStore.wallet!.privateKey!,
if (restoreHeightResult != null) ...{'height': restoreHeightResult}
};
}
@@ -201,4 +217,23 @@ abstract class WalletKeysViewModelBase with Store {
}
String getRoundedRestoreHeight(int height) => ((height / 1000).floor() * 1000).toString();
LegacySeedLang _getLegacySeedLang(PolyseedLang lang) {
switch (lang.nameEnglish) {
case "Spanish":
return LegacySeedLang.getByEnglishName("Spanish");
case "French":
return LegacySeedLang.getByEnglishName("French");
case "Italian":
return LegacySeedLang.getByEnglishName("Italian");
case "Japanese":
return LegacySeedLang.getByEnglishName("Japanese");
case "Portuguese":
return LegacySeedLang.getByEnglishName("Portuguese");
case "Chinese (Simplified)":
return LegacySeedLang.getByEnglishName("Chinese (simplified)");
default:
return LegacySeedLang.getByEnglishName("English");
}
}
}
+10 -5
View File
@@ -1,6 +1,4 @@
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
@@ -17,6 +15,8 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/haven/haven.dart';
import 'advanced_privacy_settings_view_model.dart';
import '../polygon/polygon.dart';
part 'wallet_new_vm.g.dart';
class WalletNewVM = WalletNewVMBase with _$WalletNewVM;
@@ -47,25 +47,30 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
}
}
bool get hasSeedType => type == WalletType.monero;
@override
WalletCredentials getCredentials(dynamic options) {
WalletCredentials getCredentials(dynamic _options) {
final options = _options as List<dynamic>?;
switch (type) {
case WalletType.monero:
return monero!.createMoneroNewWalletCredentials(
name: name, language: options as String);
name: name, language: options!.first as String, isPolyseed: options.last as bool);
case WalletType.bitcoin:
return bitcoin!.createBitcoinNewWalletCredentials(name: name);
case WalletType.litecoin:
return bitcoin!.createBitcoinNewWalletCredentials(name: name);
case WalletType.haven:
return haven!.createHavenNewWalletCredentials(
name: name, language: options as String);
name: name, language: options!.first as String);
case WalletType.ethereum:
return ethereum!.createEthereumNewWalletCredentials(name: name);
case WalletType.bitcoinCash:
return bitcoinCash!.createBitcoinCashNewWalletCredentials(name: name);
case WalletType.nano:
return nano!.createNanoNewWalletCredentials(name: name);
case WalletType.polygon:
return polygon!.createPolygonNewWalletCredentials(name: name);
default:
throw Exception('Unexpected type: ${type.toString()}');
}
+18 -1
View File
@@ -3,6 +3,7 @@ import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/store/app_store.dart';
@@ -28,7 +29,10 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
: hasSeedLanguageSelector = type == WalletType.monero || type == WalletType.haven,
hasBlockchainHeightLanguageSelector = type == WalletType.monero || type == WalletType.haven,
hasRestoreFromPrivateKey =
type == WalletType.ethereum || type == WalletType.nano || type == WalletType.banano,
type == WalletType.ethereum ||
type == WalletType.polygon ||
type == WalletType.nano ||
type == WalletType.banano,
isButtonEnabled = false,
mode = WalletRestoreMode.seed,
super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true) {
@@ -36,6 +40,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
case WalletType.monero:
case WalletType.haven:
case WalletType.ethereum:
case WalletType.polygon:
availableModes = WalletRestoreMode.values;
break;
case WalletType.nano:
@@ -107,6 +112,12 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
mnemonic: seed,
password: password,
derivationType: derivationType);
case WalletType.polygon:
return polygon!.createPolygonRestoreWalletFromSeedCredentials(
name: name,
mnemonic: seed,
password: password,
);
default:
break;
}
@@ -153,6 +164,12 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
password: password,
seedKey: options['private_key'] as String,
derivationType: options["derivationType"] as DerivationType);
case WalletType.polygon:
return polygon!.createPolygonRestoreWalletFromPrivateKey(
name: name,
password: password,
privateKey: options['private_key'] as String,
);
default:
break;
}