Skip to content

Commit

Permalink
Cw 462 monero polyseed restore support (#1109)
Browse files Browse the repository at this point in the history
* CW-462 Mark Places to integrate Polyseed

* CW-462 Add Restore from Polyseed

* CW-462 Add Restore from Polyseed

* CW-462 Add new Monero date-height pairs

* CW-462 Little Cleanup

* CW-462 Ups I missed that Debug line :/

* CW-462 Fix Polyseed not showing in Wallet-Seed/Keys Page

* CW-462 Prepare for Wallet creation

* CW-462 Fix merge conflict

* CW-462 Fix generating monero.dart

* CW-462 Add Polyseed generation

* CW-462 Add Polyseed Languages to SeedLanguagePicker

* CW-462 Apply requested changes

* CW-462 Minor bug fixes in restore screen

* Update wallet_restore_from_seed_form.dart

* CW-462 Minor Bugfix

* CW-462 Fix Restore from QR for Polyseeds

* CW-462 Fix null-check-operator exception for Polyseeds and minor inconveniences

* CW-462 Fix minor inconveniences

* Fix conflicts and review comments and wrap unspent issue with try and catch with reporting failure

---------

Co-authored-by: OmarHatem <[email protected]>
  • Loading branch information
konstantinullrich and OmarHatem28 authored Nov 25, 2023
1 parent eeb9976 commit 00c97c7
Show file tree
Hide file tree
Showing 57 changed files with 905 additions and 443 deletions.
36 changes: 35 additions & 1 deletion cw_core/lib/get_height_by_date.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,41 @@ final dates = {
"2020-8": 2153983,
"2020-9": 2176466,
"2020-10": 2198453,
"2020-11": 2220000
"2020-11": 2220000,
"2020-12": 2242240,
"2021-1": 2264584,
"2021-2": 2286892,
"2021-3": 2307079,
"2021-4": 2329385,
"2021-5": 2351004,
"2021-6": 2373306,
"2021-7": 2394882,
"2021-8": 2417162,
"2021-9": 2439490,
"2021-10": 2461020,
"2021-11": 2483377,
"2021-12": 2504932,
"2022-1": 2527316,
"2022-2": 2549605,
"2022-3": 2569711,
"2022-4": 2591995,
"2022-5": 2613603,
"2022-6": 2635840,
"2022-7": 2657395,
"2022-8": 2679705,
"2022-9": 2701991,
"2022-10": 2723607,
"2022-11": 2745899,
"2022-12": 2767427,
"2023-1": 2789763,
"2023-2": 2811996,
"2023-3": 2832118,
"2023-4": 2854365,
"2023-5": 2875972,
"2023-6": 2898234,
"2023-7": 2919771,
"2023-8": 2942045,
"2023-9": 2964280
};

int getMoneroHeigthByDate({required DateTime date}) {
Expand Down
4 changes: 2 additions & 2 deletions cw_core/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,10 @@ packages:
dependency: "direct dev"
description:
name: hive_generator
sha256: "81fd20125cb2ce8fd23623d7744ffbaf653aae93706c9bd3bf7019ea0ace3938"
sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
url: "https://pub.dev"
source: hosted
version: "1.1.3"
version: "2.0.1"
http:
dependency: "direct main"
description:
Expand Down
2 changes: 1 addition & 1 deletion cw_core/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ dev_dependencies:
build_runner: ^2.1.11
build_resolvers: ^2.0.9
mobx_codegen: ^2.0.7
hive_generator: ^1.1.3
hive_generator: ^2.0.1

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
Expand Down
15 changes: 12 additions & 3 deletions cw_monero/example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -301,10 +301,19 @@ packages:
dependency: transitive
description:
name: pointycastle
sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
url: "https://pub.dev"
source: hosted
version: "3.6.2"
version: "3.7.3"
polyseed:
dependency: transitive
description:
path: "."
ref: HEAD
resolved-ref: "504d58a5b147fccd3bc85a25f2e72fb32771ddd7"
url: "https://github.com/cake-tech/polyseed_dart.git"
source: git
version: "0.0.1"
process:
dependency: transitive
description:
Expand Down Expand Up @@ -416,5 +425,5 @@ packages:
source: hosted
version: "0.2.0+3"
sdks:
dart: ">=3.0.0 <4.0.0"
dart: ">=3.0.6 <4.0.0"
flutter: ">=3.7.0"
34 changes: 34 additions & 0 deletions cw_monero/ios/Classes/monero_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,35 @@ extern "C"
return true;
}

bool restore_wallet_from_spend_key(char *path, char *password, char *seed, char *language, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error)
{
Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->createDeterministicWalletFromSpendKey(
std::string(path),
std::string(password),
std::string(language),
_networkType,
(uint64_t)restoreHeight,
std::string(spendKey));

int status;
std::string errorString;

wallet->statusWithErrorString(status, errorString);

if (status != Monero::Wallet::Status_Ok || !errorString.empty())
{
error = strdup(errorString.c_str());
return false;
}

// Cache Raw to support Polyseed
wallet->setCacheAttribute("cakewallet.seed", std::string(seed));

change_current_wallet(wallet);
return true;
}

bool load_wallet(char *path, char *password, int32_t nettype)
{
nice(19);
Expand Down Expand Up @@ -438,6 +467,11 @@ extern "C"

const char *seed()
{
std::string _rawSeed = get_current_wallet()->getCacheAttribute("cakewallet.seed");
if (!_rawSeed.empty())
{
return strdup(_rawSeed.c_str());
}
return strdup(get_current_wallet()->seed().c_str());
}

Expand Down
3 changes: 3 additions & 0 deletions cw_monero/lib/api/signatures.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ typedef restore_wallet_from_seed = Int8 Function(
typedef restore_wallet_from_keys = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>,
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);

typedef restore_wallet_from_spend_key = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>,
Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);

typedef is_wallet_exist = Int8 Function(Pointer<Utf8>);

typedef load_wallet = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Int8);
Expand Down
3 changes: 3 additions & 0 deletions cw_monero/lib/api/types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ typedef RestoreWalletFromSeed = int Function(
typedef RestoreWalletFromKeys = int Function(Pointer<Utf8>, Pointer<Utf8>,
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);

typedef RestoreWalletFromSpendKey = int Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>,
Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);

typedef IsWalletExist = int Function(Pointer<Utf8>);

typedef LoadWallet = int Function(Pointer<Utf8>, Pointer<Utf8>, int);
Expand Down
77 changes: 76 additions & 1 deletion cw_monero/lib/api/wallet_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import 'package:cw_monero/api/convert_utf8_to_string.dart';
import 'package:cw_monero/api/signatures.dart';
import 'package:cw_monero/api/types.dart';
import 'package:cw_monero/api/monero_api.dart';
import 'package:cw_monero/api/wallet.dart';
import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
import 'package:cw_monero/api/exceptions/wallet_creation_exception.dart';
import 'package:cw_monero/api/exceptions/wallet_restore_from_keys_exception.dart';
Expand All @@ -25,6 +24,11 @@ final restoreWalletFromKeysNative = moneroApi
'restore_wallet_from_keys')
.asFunction<RestoreWalletFromKeys>();

final restoreWalletFromSpendKeyNative = moneroApi
.lookup<NativeFunction<restore_wallet_from_spend_key>>(
'restore_wallet_from_spend_key')
.asFunction<RestoreWalletFromSpendKey>();

final isWalletExistNative = moneroApi
.lookup<NativeFunction<is_wallet_exist>>('is_wallet_exist')
.asFunction<IsWalletExist>();
Expand Down Expand Up @@ -141,6 +145,42 @@ void restoreWalletFromKeysSync(
}
}

void restoreWalletFromSpendKeySync(
{required String path,
required String password,
required String seed,
required String language,
required String spendKey,
int nettype = 0,
int restoreHeight = 0}) {
final pathPointer = path.toNativeUtf8();
final passwordPointer = password.toNativeUtf8();
final seedPointer = seed.toNativeUtf8();
final languagePointer = language.toNativeUtf8();
final spendKeyPointer = spendKey.toNativeUtf8();
final errorMessagePointer = ''.toNativeUtf8();
final isWalletRestored = restoreWalletFromSpendKeyNative(
pathPointer,
passwordPointer,
seedPointer,
languagePointer,
spendKeyPointer,
nettype,
restoreHeight,
errorMessagePointer) !=
0;

calloc.free(pathPointer);
calloc.free(passwordPointer);
calloc.free(languagePointer);
calloc.free(spendKeyPointer);

if (!isWalletRestored) {
throw WalletRestoreFromKeysException(
message: convertUTF8ToString(pointer: errorMessagePointer));
}
}

void loadWallet({
required String path,
required String password,
Expand Down Expand Up @@ -194,6 +234,23 @@ void _restoreFromKeys(Map<String, dynamic> args) {
spendKey: spendKey);
}

void _restoreFromSpendKey(Map<String, dynamic> args) {
final path = args['path'] as String;
final password = args['password'] as String;
final seed = args['seed'] as String;
final language = args['language'] as String;
final spendKey = args['spendKey'] as String;
final restoreHeight = args['restoreHeight'] as int;

restoreWalletFromSpendKeySync(
path: path,
password: password,
seed: seed,
language: language,
restoreHeight: restoreHeight,
spendKey: spendKey);
}

Future<void> _openWallet(Map<String, String> args) async =>
loadWallet(path: args['path'] as String, password: args['password'] as String);

Expand Down Expand Up @@ -251,4 +308,22 @@ Future<void> restoreFromKeys(
'restoreHeight': restoreHeight
});

Future<void> restoreFromSpendKey(
{required String path,
required String password,
required String seed,
required String language,
required String spendKey,
int nettype = 0,
int restoreHeight = 0}) async =>
compute<Map<String, Object>, void>(_restoreFromSpendKey, {
'path': path,
'password': password,
'seed': seed,
'language': language,
'spendKey': spendKey,
'nettype': nettype,
'restoreHeight': restoreHeight
});

Future<bool> isWalletExist({required String path}) => compute(_isWalletExist, path);
89 changes: 54 additions & 35 deletions cw_monero/lib/monero_wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import 'package:cw_monero/monero_transaction_info.dart';
import 'package:cw_monero/monero_unspent.dart';
import 'package:cw_monero/monero_wallet_addresses.dart';
import 'package:cw_monero/pending_monero_transaction.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';

Expand Down Expand Up @@ -78,6 +79,8 @@ abstract class MoneroWalletBase

Box<UnspentCoinsInfo> unspentCoinsInfo;

void Function(FlutterErrorDetails)? _onError;

@override
late MoneroWalletAddresses walletAddresses;

Expand Down Expand Up @@ -388,46 +391,59 @@ abstract class MoneroWalletBase
}

Future<void> updateUnspent() async {
refreshCoins(walletAddresses.account!.id);

unspentCoins.clear();
try {
refreshCoins(walletAddresses.account!.id);

unspentCoins.clear();

final coinCount = countOfCoins();
for (var i = 0; i < coinCount; i++) {
final coin = getCoin(i);
if (coin.spent == 0) {
final unspent = MoneroUnspent.fromCoinsInfoRow(coin);
if (unspent.hash.isNotEmpty) {
unspent.isChange = transaction_history
.getTransaction(unspent.hash)
.direction == 1;
}
unspentCoins.add(unspent);
}
}

final coinCount = countOfCoins();
for (var i = 0; i < coinCount; i++) {
final coin = getCoin(i);
if (coin.spent == 0) {
final unspent = MoneroUnspent.fromCoinsInfoRow(coin);
unspent.isChange = transaction_history.getTransaction(unspent.hash).direction == 1;
unspentCoins.add(unspent);
if (unspentCoinsInfo.isEmpty) {
unspentCoins.forEach((coin) => _addCoinInfo(coin));
return;
}
}

if (unspentCoinsInfo.isEmpty) {
unspentCoins.forEach((coin) => _addCoinInfo(coin));
return;
}
if (unspentCoins.isNotEmpty) {
unspentCoins.forEach((coin) {
final coinInfoList = unspentCoinsInfo.values.where((element) =>
element.walletId.contains(id) &&
element.accountIndex == walletAddresses.account!.id &&
element.keyImage!.contains(coin.keyImage!));

if (coinInfoList.isNotEmpty) {
final coinInfo = coinInfoList.first;

coin.isFrozen = coinInfo.isFrozen;
coin.isSending = coinInfo.isSending;
coin.note = coinInfo.note;
} else {
_addCoinInfo(coin);
}
});
}

if (unspentCoins.isNotEmpty) {
unspentCoins.forEach((coin) {
final coinInfoList = unspentCoinsInfo.values.where((element) =>
element.walletId.contains(id) &&
element.accountIndex == walletAddresses.account!.id &&
element.keyImage!.contains(coin.keyImage!));

if (coinInfoList.isNotEmpty) {
final coinInfo = coinInfoList.first;

coin.isFrozen = coinInfo.isFrozen;
coin.isSending = coinInfo.isSending;
coin.note = coinInfo.note;
} else {
_addCoinInfo(coin);
}
});
await _refreshUnspentCoinsInfo();
_askForUpdateBalance();
} catch (e, s) {
print(e.toString());
_onError?.call(FlutterErrorDetails(
exception: e,
stack: s,
library: this.runtimeType.toString(),
));
}

await _refreshUnspentCoinsInfo();
_askForUpdateBalance();
}

Future<void> _addCoinInfo(MoneroUnspent coin) async {
Expand Down Expand Up @@ -632,4 +648,7 @@ abstract class MoneroWalletBase
walletAddresses.updateSubaddressList(accountIndex: account?.id ?? 0);
}
}

@override
void setExceptionHandler(void Function(FlutterErrorDetails) onError) => _onError = onError;
}
Loading

0 comments on commit 00c97c7

Please sign in to comment.