Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cw_monero/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -545,8 +545,8 @@ packages:
dependency: "direct main"
description:
path: "impls/monero.dart"
ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
resolved-ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
ref: "4f23e050f7dec0bbbbe27c36c8e511bb3f52868a"
resolved-ref: "4f23e050f7dec0bbbbe27c36c8e511bb3f52868a"
url: "https://github.com/mrcyjanek/monero_c.git"
source: git
version: "0.0.0"
Expand Down
2 changes: 1 addition & 1 deletion cw_monero/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ dependencies:
monero:
git:
url: https://github.com/mrcyjanek/monero_c.git
ref: 3bfb3856a838f2bf6b729501837bb0295dedf25d
ref: 4f23e050f7dec0bbbbe27c36c8e511bb3f52868a
path: impls/monero.dart
mutex: ^3.1.0
ledger_flutter_plus: ^1.4.1
Expand Down
4 changes: 2 additions & 2 deletions cw_wownero/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,8 @@ packages:
dependency: "direct main"
description:
path: "impls/monero.dart"
ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
resolved-ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
ref: "4f23e050f7dec0bbbbe27c36c8e511bb3f52868a"
resolved-ref: "4f23e050f7dec0bbbbe27c36c8e511bb3f52868a"
url: "https://github.com/mrcyjanek/monero_c.git"
source: git
version: "0.0.0"
Expand Down
2 changes: 1 addition & 1 deletion cw_wownero/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ dependencies:
monero:
git:
url: https://github.com/mrcyjanek/monero_c.git
ref: 3bfb3856a838f2bf6b729501837bb0295dedf25d
ref: 4f23e050f7dec0bbbbe27c36c8e511bb3f52868a
path: impls/monero.dart
mutex: ^3.1.0

Expand Down
10 changes: 8 additions & 2 deletions cw_zano/lib/api/model/transfer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,14 @@ class Transfer {
remoteAliases: json['remote_aliases'] == null ? [] : (json['remote_aliases'] as List<
dynamic>).cast<String>(),
showSender: json['show_sender'] as bool? ?? false,
subtransfers: (json['subtransfers'] as List<dynamic>? ?? []).map((e) =>
Subtransfer.fromJson(e as Map<String, dynamic>)).toList(),
subtransfers: (json['subtransfers_by_pid'] as List<dynamic>? ?? [])
.whereType<Map<String, dynamic>>()
.expand(
(group) => (group['subtransfers'] as List<dynamic>? ?? [])
.whereType<Map<String, dynamic>>()
.map(Subtransfer.fromJson),
)
.toList(),
timestamp: json['timestamp'] as int? ?? 0,
transferInternalIndex: json['transfer_internal_index'] == null
? 0
Expand Down
18 changes: 18 additions & 0 deletions cw_zano/lib/bip39_seed.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'dart:typed_data';

import 'package:bip39/bip39.dart' as bip39;

bool isBip39Seed(String mnemonic) => bip39.validateMnemonic(mnemonic);

String generateBip39Mnemonic({int strength = 128}) =>
bip39.generateMnemonic(strength: strength);

String getSecretDerivationFromBip39(String mnemonic, {String passphrase = ''}) {
final seed = bip39.mnemonicToSeed(mnemonic, passphrase: passphrase);
return Uint8List.fromList(seed.sublist(0, 32)).toHexString();
}

extension on Uint8List {
String toHexString() =>
map((b) => b.toRadixString(16).padLeft(2, '0')).join();
}
70 changes: 58 additions & 12 deletions cw_zano/lib/zano_wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import 'package:cw_zano/zano_wallet_api.dart';
import 'package:cw_zano/zano_wallet_exceptions.dart';
import 'package:cw_zano/zano_wallet_service.dart';
import 'package:cw_zano/api/model/balance.dart';
import 'package:cw_zano/bip39_seed.dart';

import 'package:mobx/mobx.dart';

Expand Down Expand Up @@ -132,14 +133,27 @@ abstract class ZanoWalletBase
final wallet = ZanoWallet(credentials.walletInfo!, await credentials.walletInfo!.getDerivationInfo(), credentials.password!);
await wallet.initWallet();
final path = await pathForWallet(name: credentials.name, type: credentials.walletInfo!.type);
final createWalletResult = await wallet.createWallet(path, credentials.password!);
final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
final providedMnemonic =
credentials is ZanoNewWalletCredentials ? credentials.mnemonic : null;
final mnemonic = providedMnemonic ?? generateBip39Mnemonic(strength: strength);
final passphrase = credentials.passphrase ?? '';
final secretDerivation = getSecretDerivationFromBip39(mnemonic, passphrase: passphrase);
final creationTimestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000;
final createWalletResult = await wallet.restoreWalletFromDerivations(
path,
credentials.password!,
secretDerivation,
creationTimestamp: creationTimestamp,
);
await wallet.initWallet();
await wallet.parseCreateWalletResult(createWalletResult);
await wallet.setBip39Secrets(mnemonic: mnemonic, creationTimestamp: creationTimestamp);
if (credentials.passphrase != null) {
await wallet.setPassphrase(credentials.passphrase!);
wallet.seed = await createWalletResult.seed(wallet);
wallet.passphrase = await wallet.getPassphrase();
}
await wallet.parseCreateWalletResult(createWalletResult);
wallet.seed = mnemonic;
wallet.passphrase = await wallet.getPassphrase();
await wallet.init(createWalletResult.wi.address);
return wallet;
}
Expand All @@ -149,15 +163,33 @@ abstract class ZanoWalletBase
final wallet = ZanoWallet(credentials.walletInfo!, await credentials.walletInfo!.getDerivationInfo(), credentials.password!);
await wallet.initWallet();
final path = await pathForWallet(name: credentials.name, type: credentials.walletInfo!.type);
final createWalletResult = await wallet.restoreWalletFromSeed(
path, credentials.password!, credentials.mnemonic, credentials.passphrase);
final passphrase = credentials.passphrase ?? '';
final CreateWalletResult createWalletResult;
if (isBip39Seed(credentials.mnemonic)) {
final secretDerivation =
getSecretDerivationFromBip39(credentials.mnemonic, passphrase: passphrase);
final creationTimestamp = (credentials.height ?? 0) > 0 ? credentials.height! : 0;
createWalletResult = await wallet.restoreWalletFromDerivations(
path,
credentials.password!,
secretDerivation,
creationTimestamp: creationTimestamp,
);
await wallet.setBip39Secrets(
mnemonic: credentials.mnemonic,
creationTimestamp: creationTimestamp,
);
} else {
createWalletResult = await wallet.restoreWalletFromSeed(
path, credentials.password!, credentials.mnemonic, credentials.passphrase);
}
await wallet.initWallet();
await wallet.parseCreateWalletResult(createWalletResult);
if (credentials.passphrase != null) {
await wallet.setPassphrase(credentials.passphrase!);
wallet.seed = await createWalletResult.seed(wallet);
wallet.passphrase = await wallet.getPassphrase();
}
await wallet.parseCreateWalletResult(createWalletResult);
wallet.seed = isBip39Seed(credentials.mnemonic) ? credentials.mnemonic : await createWalletResult.seed(wallet);
wallet.passphrase = await wallet.getPassphrase();
await wallet.init(createWalletResult.wi.address);
return wallet;
}
Expand Down Expand Up @@ -210,6 +242,19 @@ abstract class ZanoWalletBase
transactionHistory.addMany(transactions);
await transactionHistory.save();
}
await _ensureBip39DerivationInfo();
}

Future<void> _ensureBip39DerivationInfo() async {
if (await getBip39Mnemonic() == null) {
return;
}
final di = await walletInfo.getDerivationInfo();
if (di.derivationType == DerivationType.bip39) {
return;
}
di.derivationType = DerivationType.bip39;
await di.save();
}

@override
Expand Down Expand Up @@ -305,12 +350,13 @@ abstract class ZanoWalletBase
Future<Map<String, ZanoTransactionInfo>> fetchTransactions() async {
try {
final transfers = <Transfer>[];
var offset = 0;
late GetRecentTxsAndInfoResult result;
do {
result = await getRecentTxsAndInfo(offset: 0, count: _txChunkSize);
// _lastTxIndex += result.transfers.length;
result = await getRecentTxsAndInfo(offset: offset, count: _txChunkSize);
transfers.addAll(result.transfers);
} while (result.lastItemIndex + 1 < result.totalTransfers);
offset = result.lastItemIndex + 1;
} while (offset < result.totalTransfers);
return Transfer.makeMap(transfers, zanoAssets, currentDaemonHeight);
} catch (e) {
printV((e.toString()));
Expand Down
55 changes: 55 additions & 0 deletions cw_zano/lib/zano_wallet_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,25 @@ mixin ZanoWalletApi {
return _setWalletSecret("passphrase", passphrase);
}

Future<String?> getBip39Mnemonic() async {
return await _getWalletSecret("bip39_mnemonic");
}

Future<void> setBip39Secrets({
required String mnemonic,
required int creationTimestamp,
}) async {
final secrets = await _getSecrets();
secrets["bip39_mnemonic"] = mnemonic;
secrets["creation_timestamp"] = creationTimestamp.toString();
await _setSecrets(secrets);
}

Future<String> getSeed() async {
final bip39Mnemonic = await getBip39Mnemonic();
if (bip39Mnemonic != null) {
return bip39Mnemonic;
}
final passphrase = await getPassphrase();
final respStr = await invokeMethod("get_restore_info", {"seed_password": passphrase??""});
final resp = convert.json.decode(respStr);
Expand Down Expand Up @@ -319,6 +337,43 @@ mixin ZanoWalletApi {
return result;
}

Future<CreateWalletResult> restoreWalletFromDerivations(
String path,
String password,
String secretDerivation, {
bool isAuditable = false,
required int creationTimestamp,
}) async {
printV('restore_wallet_from_derivations path $path');
final params = jsonEncode({
"creation_timestamp": creationTimestamp,
"is_auditable": isAuditable,
"pass": password,
"path": path,
"secret_derivation": secretDerivation,
});
final json = await callSyncMethod('restore_from_derivations', 0, params);
final map = jsonDecode(json) as Map<String, dynamic>?;
if (map?['error'] != null) {
final code = map!['error']!['code'] ?? '';
final message = map['error']!['message'] ?? '';
if (code == Consts.errorWrongSeed) {
throw RestoreFromSeedsException(
'Error restoring wallet\nPlease check the seed words are correct. Additionally, if you created this wallet with a passphrase please add it under the Advanced Settings page.');
} else if (code == Consts.errorAlreadyExists) {
throw RestoreFromSeedsException('Error restoring wallet, already exists');
}
throw RestoreFromSeedsException('Error restoring wallet, $message ($code)');
}
if (map?['result'] == null) {
throw RestoreFromSeedsException('Error restoring wallet, empty response');
}
final result = CreateWalletResult.fromJson(map!['result'] as Map<String, dynamic>);
openWalletCache[path] = result;
printV('restore_wallet_from_derivations ${result.name} ${result.wi.address}');
return result;
}

Future<CreateWalletResult> restoreWalletFromSeed(String path, String password, String seed, String? passphrase) async {
printV('restore_wallet path $path');
final json = zano.PlainWallet_restore(seed, path, password, passphrase??'');
Expand Down
9 changes: 8 additions & 1 deletion cw_zano/lib/zano_wallet_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ import 'package:hive/hive.dart';
import 'package:monero/zano.dart' as zano;

class ZanoNewWalletCredentials extends WalletCredentials {
ZanoNewWalletCredentials({required String name, String? password, required String? passphrase}) : super(name: name, password: password, passphrase: passphrase);
ZanoNewWalletCredentials({
required String name,
String? password,
required String? passphrase,
this.mnemonic,
}) : super(name: name, password: password, passphrase: passphrase);

final String? mnemonic;
}

class ZanoRestoreWalletFromSeedCredentials extends WalletCredentials {
Expand Down
20 changes: 18 additions & 2 deletions cw_zano/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ packages:
url: "https://github.com/cake-tech/bech32.git"
source: git
version: "0.2.2"
bip39:
dependency: "direct main"
description:
name: bip39
sha256: de1ee27ebe7d96b84bb3a04a4132a0a3007dcdd5ad27dd14aa87a29d97c45edc
url: "https://pub.dev"
source: hosted
version: "1.0.6"
blockchain_utils:
dependency: transitive
description:
Expand Down Expand Up @@ -298,6 +306,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.2"
hex:
dependency: transitive
description:
name: hex
sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
hive:
dependency: "direct dev"
description:
Expand Down Expand Up @@ -454,8 +470,8 @@ packages:
dependency: "direct main"
description:
path: "impls/monero.dart"
ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
resolved-ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
ref: "4f23e050f7dec0bbbbe27c36c8e511bb3f52868a"
resolved-ref: "4f23e050f7dec0bbbbe27c36c8e511bb3f52868a"
url: "https://github.com/mrcyjanek/monero_c.git"
source: git
version: "0.0.0"
Expand Down
3 changes: 2 additions & 1 deletion cw_zano/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ environment:
dependencies:
flutter:
sdk: flutter
bip39: ^1.0.6
ffi: ^2.0.1
http: ^1.1.0
path_provider: ^2.0.11
Expand All @@ -25,7 +26,7 @@ dependencies:
monero:
git:
url: https://github.com/mrcyjanek/monero_c.git
ref: 3bfb3856a838f2bf6b729501837bb0295dedf25d
ref: 4f23e050f7dec0bbbbe27c36c8e511bb3f52868a
path: impls/monero.dart
dev_dependencies:
flutter_test:
Expand Down
3 changes: 1 addition & 2 deletions lib/core/seed_validator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/solana/solana.dart';
import 'package:cake_wallet/tron/tron.dart';
import 'package:cake_wallet/wownero/wownero.dart';
import 'package:cake_wallet/zano/zano.dart';
import 'package:cake_wallet/decred/decred.dart';
import 'package:cake_wallet/utils/language_list.dart';
import 'package:cake_wallet/zcash/zcash.dart';
Expand Down Expand Up @@ -51,7 +50,7 @@ class SeedValidator extends Validator<MnemonicItem> {
case WalletType.wownero:
return wownero!.getWowneroWordList(language);
case WalletType.zano:
return zano!.getWordList(language);
return getBitcoinWordList(language);
case WalletType.decred:
return decred!.getDecredWordList();
case WalletType.zcash:
Expand Down
3 changes: 2 additions & 1 deletion lib/core/wallet_creation_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,13 @@ class WalletCreationService {
case WalletType.nano:
case WalletType.zcash:
return true;
case WalletType.zano:
return true;
case WalletType.monero:
case WalletType.wownero:
case WalletType.none:
case WalletType.haven:
case WalletType.banano:
case WalletType.zano:
case WalletType.decred:
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/reactions/wallet_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ bool isBIP39Wallet(WalletType walletType) {
case WalletType.monero:
case WalletType.dogecoin:
case WalletType.zcash:
case WalletType.zano:
return true;
case WalletType.wownero:
case WalletType.haven:
case WalletType.zano:
case WalletType.decred:
case WalletType.none:
return false;
Expand Down
Loading
Loading