diff --git a/configure_cake_wallet_android.sh b/configure_cake_wallet_android.sh old mode 100644 new mode 100755 diff --git a/cw_nano/lib/nano_client.dart b/cw_nano/lib/nano_client.dart index 80943fd1f..1c51d7b76 100644 --- a/cw_nano/lib/nano_client.dart +++ b/cw_nano/lib/nano_client.dart @@ -16,7 +16,7 @@ import 'package:cw_core/node.dart'; class NanoClient { // bit of a hack since we need access to a node in a weird location: - static const String BACKUP_NODE_URI = "rpc.nano.to"; + static const String BACKUP_NODE_URI = "rpc.nano.to:443"; static const String DEFAULT_REPRESENTATIVE = "nano_38713x95zyjsqzx6nm1dsom1jmm668owkeb9913ax6nfgj15az3nu8xkx579"; diff --git a/cw_nano/lib/nano_util.dart b/cw_nano/lib/nano_util.dart index 3cb66afaf..ee283ab35 100644 --- a/cw_nano/lib/nano_util.dart +++ b/cw_nano/lib/nano_util.dart @@ -27,6 +27,10 @@ class NanoUtil { return NanoMnemomics.seedToMnemonic(seed).join(" "); } + static Future mnemonicToSeed(String mnemonic) async { + return NanoMnemomics.mnemonicListToSeed(mnemonic.split(' ')); + } + // static String createPublicKey(String privateKey) { // return NanoHelpers.byteToHex(Ed25519Blake2b.getPubkey(NanoHelpers.hexToBytes(privateKey))!); // } @@ -60,15 +64,15 @@ class NanoUtil { } // // hd: - // static Future hdMnemonicListToSeed(List words) async { - // // if (words.length != 24) { - // // throw Exception('Expected a 24-word list, got a ${words.length} list'); - // // } - // final Uint8List salt = Uint8List.fromList(utf8.encode('mnemonic')); - // final Pbkdf2 hasher = Pbkdf2(iterations: 2048); - // final String seed = await hasher.sha512(words.join(' '), salt); - // return seed; - // } + static Future hdMnemonicListToSeed(List words) async { + // if (words.length != 24) { + // throw Exception('Expected a 24-word list, got a ${words.length} list'); + // } + final Uint8List salt = Uint8List.fromList(utf8.encode('mnemonic')); + final Pbkdf2 hasher = Pbkdf2(iterations: 2048); + final String seed = await hasher.sha512(words.join(' '), salt); + return seed; + } static Future hdSeedToPrivate(String seed, int index) async { List seedBytes = hex.decode(seed); @@ -101,6 +105,8 @@ class NanoUtil { } } + + // static String hdSeedToPrivate(String seed, int index) { // // List seedBytes = hex.decode(seed); // // KeyData data = await ED25519_HD_KEY.derivePath("m/44'/165'/$index'", seedBytes); diff --git a/cw_nano/lib/nano_wallet.dart b/cw_nano/lib/nano_wallet.dart index 5be34fbce..6df5e4f9f 100644 --- a/cw_nano/lib/nano_wallet.dart +++ b/cw_nano/lib/nano_wallet.dart @@ -18,7 +18,6 @@ import 'package:cw_nano/nano_transaction_credentials.dart'; import 'package:cw_nano/nano_transaction_history.dart'; import 'package:cw_nano/nano_transaction_info.dart'; import 'package:cw_nano/nano_util.dart'; -import 'package:cw_nano/nano_wallet_info.dart'; import 'package:cw_nano/nano_wallet_keys.dart'; import 'package:cw_nano/pending_nano_transaction.dart'; import 'package:mobx/mobx.dart'; @@ -37,14 +36,14 @@ class NanoWallet = NanoWalletBase with _$NanoWallet; abstract class NanoWalletBase extends WalletBase with Store { NanoWalletBase({ - required NanoWalletInfo walletInfo, + required WalletInfo walletInfo, required String mnemonic, required String password, NanoBalance? initialBalance, }) : syncStatus = NotConnectedSyncStatus(), _password = password, _mnemonic = mnemonic, - _derivationType = walletInfo.derivationType, + _derivationType = walletInfo.derivationType!, _isTransactionUpdating = false, _client = NanoClient(), walletAddresses = NanoWalletAddresses(walletInfo), @@ -88,7 +87,14 @@ abstract class NanoWalletBase // initialize the different forms of private / public key we'll need: Future init() async { final String type = (_derivationType == DerivationType.nano) ? "standard" : "hd"; - _seedKey = bip39.mnemonicToEntropy(_mnemonic).toUpperCase(); + + if (_seedKey == null) { + if (_derivationType == DerivationType.nano) { + _seedKey = bip39.mnemonicToEntropy(_mnemonic).toUpperCase(); + } else { + _seedKey = await NanoUtil.hdMnemonicListToSeed(_mnemonic.split(' ')); + } + } _privateKey = await NanoUtil.uniSeedToPrivate(_seedKey!, 0, type); _publicAddress = await NanoUtil.uniSeedToAddress(_seedKey!, 0, type); this.walletInfo.address = _publicAddress!; @@ -339,13 +345,10 @@ abstract class NanoWalletBase derivationType = DerivationType.nano; } - final nanoWalletInfo = NanoWalletInfo( - walletInfo: walletInfo, - derivationType: derivationType, - ); + walletInfo.derivationType = derivationType; return NanoWallet( - walletInfo: nanoWalletInfo, + walletInfo: walletInfo, password: password, mnemonic: mnemonic, initialBalance: balance, diff --git a/cw_nano/lib/nano_wallet_info.dart b/cw_nano/lib/nano_wallet_info.dart deleted file mode 100644 index 2d437e848..000000000 --- a/cw_nano/lib/nano_wallet_info.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:cw_core/wallet_info.dart'; - -enum DerivationType { bip39, nano } - -class NanoWalletInfo extends WalletInfo { - DerivationType derivationType; - - NanoWalletInfo({required WalletInfo walletInfo, required this.derivationType}) - : super( - walletInfo.id, - walletInfo.name, - walletInfo.type, - walletInfo.isRecovery, - walletInfo.restoreHeight, - walletInfo.timestamp, - walletInfo.dirPath, - walletInfo.path, - walletInfo.address, - walletInfo.yatEid, - walletInfo.yatLastUsedAddressRaw, - walletInfo.showIntroCakePayCard, - ); -} diff --git a/cw_nano/lib/nano_wallet_service.dart b/cw_nano/lib/nano_wallet_service.dart index 63ed07289..049fe2c5d 100644 --- a/cw_nano/lib/nano_wallet_service.dart +++ b/cw_nano/lib/nano_wallet_service.dart @@ -12,7 +12,6 @@ import 'package:cw_nano/nano_client.dart'; import 'package:cw_nano/nano_mnemonic.dart' as nm; import 'package:cw_nano/nano_util.dart'; import 'package:cw_nano/nano_wallet.dart'; -import 'package:cw_nano/nano_wallet_info.dart'; import 'package:hive/hive.dart'; import 'package:bip39/bip39.dart' as bip39; import 'package:nanodart/nanodart.dart'; @@ -75,13 +74,10 @@ class NanoWalletService extends WalletService info.id == WalletBase.idFor(currentName, getType())); - final NanoWalletInfo nanoWalletInfo = NanoWalletInfo( - walletInfo: currentWalletInfo, - derivationType: DerivationType.nano, // doesn't matter for rename - ); + currentWalletInfo.derivationType = DerivationType.nano;// doesn't matter for the rename action String randomWords = (List.from(nm.NanoMnemomics.WORDLIST)..shuffle()).take(24).join(' '); final currentWallet = - NanoWallet(walletInfo: nanoWalletInfo, password: password, mnemonic: randomWords); + NanoWallet(walletInfo: currentWalletInfo, password: password, mnemonic: randomWords); await currentWallet.renameWalletFiles(newName); @@ -128,13 +121,18 @@ class NanoWalletService extends WalletService compareDerivationMethods({String? mnemonic, String? seedKey}) async { - if (seedKey?.length == 128) { - return DerivationType.bip39; - } + static Future compareDerivationMethods({String? mnemonic, String? seedKey}) async { if (mnemonic?.split(' ').length == 12) { return DerivationType.bip39; } + if (seedKey?.length == 128) { + return DerivationType.bip39; + } else if (seedKey?.length == 64) { + return DerivationType.nano; + } + + late String publicAddressStandard; + late String publicAddressBip39; try { NanoClient nanoClient = NanoClient(); @@ -144,24 +142,68 @@ class NanoWalletService extends WalletService standardBalance.currentBalance) { + // return DerivationType.bip39; + // } else { + // return DerivationType.nano; + // } + + // check if account has a history: + var bip39Info; + var standardInfo; + + print(publicAddressBip39); + print(publicAddressStandard); + + try { + bip39Info = await nanoClient.getAccountInfo(publicAddressBip39); + } catch (e) { + bip39Info = null; + } + try { + standardInfo = await nanoClient.getAccountInfo(publicAddressStandard); + } catch (e) { + standardInfo = null; } - publicAddressBip39 = await NanoUtil.hdSeedToAddress(seedKey, 0); - publicAddressStandard = await NanoUtil.seedToAddress(seedKey, 0); + // one of these is *probably* null: + if (bip39Info == null || bip39Info["error"] != null) { + return DerivationType.nano; + } else if (standardInfo == null || standardInfo["error"] != null) { + return DerivationType.bip39; + } - // check if either has a balance: + // both are non-null: + var bip39Height = int.parse(bip39Info['confirmation_height'] as String); + var standardHeight = int.parse(standardInfo['confirmation_height'] as String); - NanoBalance bip39Balance = await nanoClient.getBalance(publicAddressBip39); - NanoBalance standardBalance = await nanoClient.getBalance(publicAddressStandard); + print(bip39Height); + print(standardHeight); - // TODO: this is a super basic implementation, and if both addresses have balances - // it might not be the one that the user wants, though it is unlikely - if (bip39Balance.currentBalance > standardBalance.currentBalance) { + if (bip39Height > standardHeight) { return DerivationType.bip39; } else { return DerivationType.nano; @@ -207,15 +249,12 @@ class NanoWalletService extends WalletService initializeAppConfigs() async { Hive.registerAdapter(WalletInfoAdapter()); } + if (!Hive.isAdapterRegistered(derivationTypeTypeId)) { + Hive.registerAdapter(DerivationTypeAdapter()); + } + if (!Hive.isAdapterRegistered(walletTypeTypeId)) { Hive.registerAdapter(WalletTypeAdapter()); } diff --git a/lib/nano/cw_nano.dart b/lib/nano/cw_nano.dart index a32b6e932..ea1fa2fbf 100644 --- a/lib/nano/cw_nano.dart +++ b/lib/nano/cw_nano.dart @@ -108,13 +108,24 @@ class CWNano extends Nano { required String password, required String mnemonic, DerivationType? derivationType, - }) => - NanoRestoreWalletFromSeedCredentials( - name: name, - password: password, - mnemonic: mnemonic, - derivationType: derivationType, - ); + }) { + + if (derivationType == null) { + // figure out the derivation type as best we can, otherwise set it to "unknown" + if (mnemonic.split(" ").length == 12) { + derivationType = DerivationType.bip39; + } else { + derivationType = DerivationType.unknown; + } + } + + return NanoRestoreWalletFromSeedCredentials( + name: name, + password: password, + mnemonic: mnemonic, + derivationType: derivationType, + ); + } @override TransactionHistoryBase getTransactionHistory(Object wallet) { diff --git a/lib/nano/nano.dart b/lib/nano/nano.dart index 90be9f04c..c22ce60df 100644 --- a/lib/nano/nano.dart +++ b/lib/nano/nano.dart @@ -1,3 +1,4 @@ + import 'package:cw_core/nano_account.dart'; import 'package:cw_nano/nano_mnemonic.dart'; import 'package:cw_nano/nano_wallet.dart'; @@ -6,12 +7,14 @@ import 'package:cake_wallet/view_model/send/output.dart'; import 'package:cw_core/account.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/wallet_credentials.dart'; -import 'package:cw_nano/nano_wallet_info.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/output_info.dart'; import 'package:hive/hive.dart'; +import 'package:cw_nano/api/wallet.dart' as nano_wallet_api; +import 'package:cw_nano/nano_balance.dart'; +import 'package:cw_nano/nano_wallet_creation_credentials.dart'; import 'package:cw_nano/nano_transaction_credentials.dart'; part 'cw_nano.dart'; @@ -33,7 +36,7 @@ abstract class Nano { required String name, String password, }); - + WalletCredentials createNanoRestoreWalletFromSeedCredentials({ required String name, required String password, @@ -58,3 +61,4 @@ abstract class NanoAccountList { Future addAccount(Object wallet, {required String label}); Future setLabelAccount(Object wallet, {required int accountIndex, required String label}); } + \ No newline at end of file diff --git a/lib/src/screens/restore/wallet_restore_page.dart b/lib/src/screens/restore/wallet_restore_page.dart index 6adf9b858..6fc237bcd 100644 --- a/lib/src/screens/restore/wallet_restore_page.dart +++ b/lib/src/screens/restore/wallet_restore_page.dart @@ -1,6 +1,7 @@ import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; +import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -91,8 +92,7 @@ class WalletRestorePage extends BasePage { fontSize: 18.0, fontWeight: FontWeight.bold, fontFamily: 'Lato', - color: titleColor ?? - Theme.of(context).primaryTextTheme!.titleLarge!.color!), + color: titleColor ?? Theme.of(context).primaryTextTheme!.titleLarge!.color!), )); final WalletRestoreViewModel walletRestoreViewModel; @@ -139,10 +139,7 @@ class WalletRestorePage extends BasePage { return KeyboardActions( config: KeyboardActionsConfig( keyboardActionsPlatform: KeyboardActionsPlatform.IOS, - keyboardBarColor: Theme.of(context) - .accentTextTheme! - .bodyLarge! - .backgroundColor!, + keyboardBarColor: Theme.of(context).accentTextTheme!.bodyLarge!.backgroundColor!, nextFocus: false, actions: [ KeyboardActionsItem( @@ -192,16 +189,13 @@ class WalletRestorePage extends BasePage { child: Observer( builder: (context) { return LoadingPrimaryButton( - onPressed: _confirmForm, + onPressed: () async { + _confirmForm(context); + }, text: S.of(context).restore_recover, - color: Theme.of(context) - .accentTextTheme! - .titleSmall! - .decorationColor!, - textColor: Theme.of(context) - .accentTextTheme! - .headlineSmall! - .decorationColor!, + color: Theme.of(context).accentTextTheme!.titleSmall!.decorationColor!, + textColor: + Theme.of(context).accentTextTheme!.headlineSmall!.decorationColor!, isLoading: walletRestoreViewModel.state is IsExecutingState, isDisabled: !walletRestoreViewModel.isButtonEnabled, ); @@ -265,7 +259,7 @@ class WalletRestorePage extends BasePage { return credentials; } - void _confirmForm() { + void _confirmForm(BuildContext context) { // Dismissing all visible keyboard to provide context for navigation FocusManager.instance.primaryFocus?.unfocus(); final formContext = walletRestoreViewModel.mode == WalletRestoreMode.seed @@ -289,6 +283,11 @@ class WalletRestorePage extends BasePage { return; } + var credentials = walletRestoreViewModel.getCredentials(_credentials()); + if (credentials.walletInfo?.derivationType == DerivationType.unknown) { + + } + walletRestoreViewModel.create(options: _credentials()); } diff --git a/lib/view_model/wallet_restore_view_model.dart b/lib/view_model/wallet_restore_view_model.dart index 9f19dcc3c..dc461de69 100644 --- a/lib/view_model/wallet_restore_view_model.dart +++ b/lib/view_model/wallet_restore_view_model.dart @@ -2,7 +2,6 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/nano/nano.dart'; import 'package:cake_wallet/ethereum/ethereum.dart'; import 'package:cw_nano/nano_wallet.dart'; -import 'package:cw_nano/nano_wallet_info.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/store/app_store.dart';