mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-11 05:14:46 +00:00
save
This commit is contained in:
parent
adc98f34cc
commit
a4e7acf875
11 changed files with 142 additions and 100 deletions
0
configure_cake_wallet_android.sh
Normal file → Executable file
0
configure_cake_wallet_android.sh
Normal file → Executable file
|
@ -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";
|
||||
|
||||
|
|
|
@ -27,6 +27,10 @@ class NanoUtil {
|
|||
return NanoMnemomics.seedToMnemonic(seed).join(" ");
|
||||
}
|
||||
|
||||
static Future<String> 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<String> hdMnemonicListToSeed(List<String> 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<String> hdMnemonicListToSeed(List<String> 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<String> hdSeedToPrivate(String seed, int index) async {
|
||||
List<int> seedBytes = hex.decode(seed);
|
||||
|
@ -101,6 +105,8 @@ class NanoUtil {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// static String hdSeedToPrivate(String seed, int index) {
|
||||
// // List<int> seedBytes = hex.decode(seed);
|
||||
// // KeyData data = await ED25519_HD_KEY.derivePath("m/44'/165'/$index'", seedBytes);
|
||||
|
|
|
@ -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<NanoBalance, NanoTransactionHistory, NanoTransactionInfo> 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<void> 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,
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
|
@ -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<NanoNewWalletCredentials,
|
|||
// derivationType derivationType = DerivationType.bip39;
|
||||
// String mnemonic = bip39.generateMnemonic();
|
||||
|
||||
final nanoWalletInfo = NanoWalletInfo(
|
||||
walletInfo: credentials.walletInfo!,
|
||||
derivationType: derivationType,
|
||||
);
|
||||
credentials.walletInfo!.derivationType = derivationType;
|
||||
|
||||
final wallet = NanoWallet(
|
||||
walletInfo: nanoWalletInfo,
|
||||
walletInfo: credentials.walletInfo!,
|
||||
mnemonic: mnemonic,
|
||||
password: credentials.password!,
|
||||
);
|
||||
|
@ -109,15 +105,12 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
|||
final currentWalletInfo = walletInfoSource.values
|
||||
.firstWhere((info) => 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<String>.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<NanoNewWalletCredentials,
|
|||
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
|
||||
}
|
||||
|
||||
Future<DerivationType> compareDerivationMethods({String? mnemonic, String? seedKey}) async {
|
||||
if (seedKey?.length == 128) {
|
||||
return DerivationType.bip39;
|
||||
}
|
||||
static Future<DerivationType> 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<NanoNewWalletCredentials,
|
|||
type: WalletType.nano,
|
||||
));
|
||||
|
||||
late String publicAddressStandard;
|
||||
late String publicAddressBip39;
|
||||
if (mnemonic != null) {
|
||||
seedKey = await NanoUtil.hdMnemonicListToSeed(mnemonic.split(' '));
|
||||
publicAddressBip39 = await NanoUtil.hdSeedToAddress(seedKey, 0);
|
||||
|
||||
if (seedKey == null) {
|
||||
seedKey = bip39.mnemonicToEntropy(mnemonic).toUpperCase();
|
||||
seedKey = await NanoUtil.mnemonicToSeed(mnemonic);
|
||||
publicAddressStandard = await NanoUtil.seedToAddress(seedKey, 0);
|
||||
} else if (seedKey != null) {
|
||||
try {
|
||||
publicAddressBip39 = await NanoUtil.hdSeedToAddress(seedKey, 0);
|
||||
} catch (e) {
|
||||
return DerivationType.nano;
|
||||
}
|
||||
try {
|
||||
publicAddressStandard = await NanoUtil.seedToAddress(seedKey, 0);
|
||||
} catch (e) {
|
||||
return DerivationType.bip39;
|
||||
}
|
||||
}
|
||||
// check if either has a balance:
|
||||
// NanoBalance bip39Balance = await nanoClient.getBalance(publicAddressBip39);
|
||||
// NanoBalance standardBalance = await nanoClient.getBalance(publicAddressStandard);
|
||||
// // 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) {
|
||||
// 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<NanoNewWalletCredentials,
|
|||
DerivationType derivationType = credentials.derivationType ??
|
||||
await compareDerivationMethods(mnemonic: credentials.mnemonic);
|
||||
|
||||
final nanoWalletInfo = NanoWalletInfo(
|
||||
walletInfo: credentials.walletInfo!,
|
||||
derivationType: derivationType,
|
||||
);
|
||||
credentials.walletInfo!.derivationType = derivationType;
|
||||
|
||||
final wallet = await NanoWallet(
|
||||
password: credentials.password!,
|
||||
mnemonic: credentials.mnemonic,
|
||||
walletInfo: nanoWalletInfo,
|
||||
walletInfo: credentials.walletInfo!,
|
||||
);
|
||||
|
||||
await wallet.init();
|
||||
|
|
|
@ -91,6 +91,10 @@ Future<void> initializeAppConfigs() async {
|
|||
Hive.registerAdapter(WalletInfoAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(derivationTypeTypeId)) {
|
||||
Hive.registerAdapter(DerivationTypeAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(walletTypeTypeId)) {
|
||||
Hive.registerAdapter(WalletTypeAdapter());
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<void> addAccount(Object wallet, {required String label});
|
||||
Future<void> setLabelAccount(Object wallet, {required int accountIndex, required String label});
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Reference in a new issue