wallet recovery

This commit is contained in:
leo 2023-12-14 04:51:16 +00:00
parent 2d886e1213
commit 8d3dd6f202
23 changed files with 2357 additions and 2000 deletions

View file

@ -96,6 +96,8 @@ class AmountConverter {
case CryptoCurrency.xnzd:
case CryptoCurrency.xusd:
return _moneroAmountToString(amount);
case CryptoCurrency.zano:
return _moneroAmountToString(amount);
default:
return '';
}

View file

@ -1,10 +1,13 @@
import 'package:cw_core/balance.dart';
import 'package:cw_core/pathForWallet.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_credentials.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart';
import 'dummy_wallet_creation_credentials.dart';
@ -15,7 +18,7 @@ class DummyWalletService extends WalletService<DummyNewWalletCredentials, DummyR
final Box<WalletInfo> walletInfoSource;
@override
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>> create(DummyNewWalletCredentials credentials) => throw UnimplementedError();
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>> create(WalletCredentials credentials) => throw UnimplementedError();
@override
WalletType getType() => WalletType.dummy;

View file

@ -20,6 +20,9 @@ dependencies:
cw_core:
path: ../cw_core
cw_zano:
path: ../cw_zano
dev_dependencies:
flutter_test:
sdk: flutter

View file

@ -419,6 +419,12 @@ extern "C"
return strdup(plain_wallet::get_wallet_status(hwallet).c_str());
}
char* get_address_info(char* address)
{
return strdup(plain_wallet::get_address_info(address).c_str());
}
char* async_call(char* method_name, uint64_t instance_id, char* params)
{
return strdup(plain_wallet::async_call(method_name, instance_id, params).c_str());

View file

@ -3,7 +3,7 @@ import 'dart:convert';
import 'package:cw_zano/api/model/recent_history.dart';
import 'package:cw_zano/api/model/wi.dart';
class CreateLoadRestoreWalletResult {
class CreateWalletResult {
final String name;
final String pass;
final RecentHistory recentHistory;
@ -14,7 +14,7 @@ class CreateLoadRestoreWalletResult {
final int walletLocalBcSize;
final Wi wi;
CreateLoadRestoreWalletResult(
CreateWalletResult(
{required this.name,
required this.pass,
required this.recentHistory,
@ -25,8 +25,8 @@ class CreateLoadRestoreWalletResult {
required this.walletLocalBcSize,
required this.wi});
factory CreateLoadRestoreWalletResult.fromJson(Map<String, dynamic> json) =>
CreateLoadRestoreWalletResult(
factory CreateWalletResult.fromJson(Map<String, dynamic> json) =>
CreateWalletResult(
name: json['name'] as String,
pass: json['pass'] as String,
recentHistory: RecentHistory.fromJson(

View file

@ -62,7 +62,7 @@ class History {
.map((e) => Subtransfer.fromJson(e as Map<String, dynamic>))
.toList(),
timestamp: json['timestamp'] as int,
transferInternalIndex: json['transfer_internal_index'] as int,
transferInternalIndex: json['transfer_internal_index'] is double ? (json['transfer_internal_index'] as double).toInt() : json['transfer_internal_index'] as int,
txBlobSize: json['tx_blob_size'] as int,
txHash: json['tx_hash'] as String,
txType: json['tx_type'] as int,

View file

@ -0,0 +1,12 @@
class ZanoWalletKeys {
const ZanoWalletKeys(
{required this.privateSpendKey,
required this.privateViewKey,
required this.publicSpendKey,
required this.publicViewKey});
final String publicViewKey;
final String privateViewKey;
final String publicSpendKey;
final String privateSpendKey;
}

View file

@ -32,9 +32,9 @@ final transactionCreateMultDestNative = zanoApi
'transaction_create_mult_dest')
.asFunction<TransactionCreateMultDest>();
final transactionCommitNative = zanoApi
.lookup<NativeFunction<transaction_commit>>('transaction_commit')
.asFunction<TransactionCommit>();
// final transactionCommitNative = zanoApi
// .lookup<NativeFunction<transaction_commit>>('transaction_commit')
// .asFunction<TransactionCommit>();
final getTxKeyNative = zanoApi
.lookup<NativeFunction<get_tx_key>>('get_tx_key')
@ -53,11 +53,11 @@ String getTxKey(String txId) {
return '';
}
void refreshTransactions() {
// TODO: fix it
//transactionsRefreshNative();
debugPrint("refreshing transactions");
}
// void refreshTransactions() {
// // TODO: fix it
// //transactionsRefreshNative();
// debugPrint("refreshing transactions");
// }
int countOfTransactions() {
//return transactionsCountNative();
@ -184,8 +184,9 @@ void commitTransactionFromPointerAddress({required int address}) =>
void commitTransaction(
{required Pointer<PendingTransactionRaw> transactionPointer}) {
final errorMessagePointer = calloc<Utf8Box>();
final isCommited =
transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
print("commit transaction");
final isCommited = true;
//transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
if (!isCommited) {
final message = errorMessagePointer.ref.getValue();

View file

@ -1,5 +1,12 @@
import 'dart:async';
import 'dart:convert';
import 'dart:ffi';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_zano/api/model/get_wallet_info_result.dart';
import 'package:cw_zano/api/model/get_wallet_status_result.dart';
import 'package:cw_zano/api/model/zano_wallet_keys.dart';
import 'package:cw_zano/zano_balance.dart';
import 'package:cw_zano/zano_wallet.dart';
import 'package:ffi/ffi.dart';
import 'package:cw_zano/api/structs/ut8_box.dart';
import 'package:cw_zano/api/convert_utf8_to_string.dart';
@ -10,19 +17,18 @@ import 'package:cw_zano/api/calls.dart' as calls;
import 'package:cw_zano/api/exceptions/setup_wallet_exception.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:mobx/mobx.dart' as mobx;
int _boolToInt(bool value) => value ? 1 : 0;
final getFileNameNative = zanoApi
.lookup<NativeFunction<get_filename>>('get_filename')
.asFunction<GetFilename>();
final getFileNameNative =
zanoApi.lookup<NativeFunction<get_filename>>('get_filename').asFunction<GetFilename>();
/*final getSeedNative =
zanoApi.lookup<NativeFunction<get_seed>>('seed').asFunction<GetSeed>();*/
final getAddressNative = zanoApi
.lookup<NativeFunction<get_address>>('get_address')
.asFunction<GetAddress>();
final getAddressNative =
zanoApi.lookup<NativeFunction<get_address>>('get_address').asFunction<GetAddress>();
final getFullBalanceNative = zanoApi
.lookup<NativeFunction<get_full_balanace>>('get_full_balance')
@ -36,42 +42,36 @@ final getUnlockedBalanceNative = zanoApi
.lookup<NativeFunction<get_current_height>>('get_current_height')
.asFunction<GetCurrentHeight>();*/
final getNodeHeightNative = zanoApi
.lookup<NativeFunction<get_node_height>>('get_node_height')
.asFunction<GetNodeHeight>();
// final getNodeHeightNative = zanoApi
// .lookup<NativeFunction<get_node_height>>('get_node_height')
// .asFunction<GetNodeHeight>();
final isConnectedNative = zanoApi
.lookup<NativeFunction<is_connected>>('is_connected')
.asFunction<IsConnected>();
final isConnectedNative =
zanoApi.lookup<NativeFunction<is_connected>>('is_connected').asFunction<IsConnected>();
final setupNodeNative = zanoApi
.lookup<NativeFunction<setup_node>>('setup_node')
.asFunction<SetupNode>();
final setupNodeNative =
zanoApi.lookup<NativeFunction<setup_node>>('setup_node').asFunction<SetupNode>();
final startRefreshNative = zanoApi
.lookup<NativeFunction<start_refresh>>('start_refresh')
.asFunction<StartRefresh>();
// final startRefreshNative = zanoApi
// .lookup<NativeFunction<start_refresh>>('start_refresh')
// .asFunction<StartRefresh>();
final connecToNodeNative = zanoApi
.lookup<NativeFunction<connect_to_node>>('connect_to_node')
.asFunction<ConnectToNode>();
final connecToNodeNative =
zanoApi.lookup<NativeFunction<connect_to_node>>('connect_to_node').asFunction<ConnectToNode>();
final setRefreshFromBlockHeightNative = zanoApi
.lookup<NativeFunction<set_refresh_from_block_height>>(
'set_refresh_from_block_height')
.lookup<NativeFunction<set_refresh_from_block_height>>('set_refresh_from_block_height')
.asFunction<SetRefreshFromBlockHeight>();
final setRecoveringFromSeedNative = zanoApi
.lookup<NativeFunction<set_recovering_from_seed>>(
'set_recovering_from_seed')
.asFunction<SetRecoveringFromSeed>();
// final setRecoveringFromSeedNative = zanoApi
// .lookup<NativeFunction<set_recovering_from_seed>>('set_recovering_from_seed')
// .asFunction<SetRecoveringFromSeed>();
final storeNative =
zanoApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
final setPasswordNative = zanoApi
.lookup<NativeFunction<set_password>>('set_password')
.asFunction<SetPassword>();
final storeNative = zanoApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
final setPasswordNative =
zanoApi.lookup<NativeFunction<set_password>>('set_password').asFunction<SetPassword>();
/**final setListenerNative = zanoApi
.lookup<NativeFunction<set_listener>>('set_listener')
@ -85,18 +85,15 @@ final isNeededToRefreshNative = zanoApi
.lookup<NativeFunction<is_needed_to_refresh>>('is_needed_to_refresh')
.asFunction<IsNeededToRefresh>();
final isNewTransactionExistNative = zanoApi
.lookup<NativeFunction<is_new_transaction_exist>>(
'is_new_transaction_exist')
.asFunction<IsNewTransactionExist>();
// final isNewTransactionExistNative = zanoApi
// .lookup<NativeFunction<is_new_transaction_exist>>('is_new_transaction_exist')
// .asFunction<IsNewTransactionExist>();
final getSecretViewKeyNative = zanoApi
.lookup<NativeFunction<secret_view_key>>('secret_view_key')
.asFunction<SecretViewKey>();
final getSecretViewKeyNative =
zanoApi.lookup<NativeFunction<secret_view_key>>('secret_view_key').asFunction<SecretViewKey>();
final getPublicViewKeyNative = zanoApi
.lookup<NativeFunction<public_view_key>>('public_view_key')
.asFunction<PublicViewKey>();
final getPublicViewKeyNative =
zanoApi.lookup<NativeFunction<public_view_key>>('public_view_key').asFunction<PublicViewKey>();
final getSecretSpendKeyNative = zanoApi
.lookup<NativeFunction<secret_spend_key>>('secret_spend_key')
@ -110,27 +107,25 @@ final closeCurrentWalletNative = zanoApi
.lookup<NativeFunction<close_current_wallet>>('close_current_wallet')
.asFunction<CloseCurrentWallet>();
final onStartupNative = zanoApi
.lookup<NativeFunction<on_startup>>('on_startup')
.asFunction<OnStartup>();
final onStartupNative =
zanoApi.lookup<NativeFunction<on_startup>>('on_startup').asFunction<OnStartup>();
final rescanBlockchainAsyncNative = zanoApi
.lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
.asFunction<RescanBlockchainAsync>();
final setTrustedDaemonNative = zanoApi
.lookup<NativeFunction<set_trusted_daemon>>('set_trusted_daemon')
.asFunction<SetTrustedDaemon>();
// final setTrustedDaemonNative = zanoApi
// .lookup<NativeFunction<set_trusted_daemon>>('set_trusted_daemon')
// .asFunction<SetTrustedDaemon>();
final trustedDaemonNative = zanoApi
.lookup<NativeFunction<trusted_daemon>>('trusted_daemon')
.asFunction<TrustedDaemon>();
final trustedDaemonNative =
zanoApi.lookup<NativeFunction<trusted_daemon>>('trusted_daemon').asFunction<TrustedDaemon>();
int getSyncingHeight() => getSyncingHeightNative();
bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
bool isNewTransactionExist() => isNewTransactionExistNative() != 0;
//bool isNewTransactionExist() => isNewTransactionExistNative() != 0;
String getFilename() => convertUTF8ToString(pointer: getFileNameNative());
@ -139,29 +134,49 @@ String getFilename() => convertUTF8ToString(pointer: getFileNameNative());
String getAddress({int accountIndex = 0, int addressIndex = 0}) =>
convertUTF8ToString(pointer: getAddressNative(accountIndex, addressIndex));
int getFullBalance({int accountIndex = 0}) =>
getFullBalanceNative(accountIndex);
int getFullBalance({int accountIndex = 0}) => getFullBalanceNative(accountIndex);
int getUnlockedBalance({int accountIndex = 0}) =>
getUnlockedBalanceNative(accountIndex);
int getUnlockedBalance({int accountIndex = 0}) => getUnlockedBalanceNative(accountIndex);
int getCurrentHeight(int hWallet) {
calls.getWalletStatus(hWallet);
return -1;
//return getCurrentHeightNative();
final json = calls.getWalletStatus(hWallet);
final walletStatus = GetWalletStatusResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
return walletStatus.currentWalletHeight;
}
int getNodeHeightSync() => getNodeHeightNative();
int getNodeHeightSync(int hWallet) {
final json = calls.getWalletStatus(hWallet);
final walletStatus = GetWalletStatusResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
return walletStatus.currentDaemonHeight;
}
// int getWalletInfo(int hWallet) {
// final json = calls.getWalletInfo(hWallet);
// final walletInfo = GetWalletInfoResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
// zanoSeed = walletInfo.wiExtended.seed;
// zanoKeys = ZanoWalletKeys(
// privateSpendKey: walletInfo.wiExtended.spendPrivateKey,
// privateViewKey: walletInfo.wiExtended.viewPrivateKey,
// publicSpendKey: walletInfo.wiExtended.spendPublicKey,
// publicViewKey: walletInfo.wiExtended.viewPublicKey,
// );
// return 0;
// }
int getTxFee(int priority) {
return calls.getCurrentTxFee(priority);
}
bool isConnectedSync() => isConnectedNative() != 0;
bool setupNodeSync(
{required String address,
String? login,
String? password,
bool useSSL = false,
bool isLightWallet = false,
/*String? socksProxyAddress*/}) {
bool setupNodeSync({
required String address,
String? login,
String? password,
bool useSSL = false,
bool isLightWallet = false,
/*String? socksProxyAddress*/
}) {
final addressPointer = address.toNativeUtf8();
Pointer<Utf8>? loginPointer;
Pointer<Utf8>? socksProxyAddressPointer;
@ -180,7 +195,8 @@ bool setupNodeSync(
}*/
final errorMessagePointer = ''.toNativeUtf8();
debugPrint("setup_node address $address login $login password $password useSSL $useSSL isLightWallet $isLightWallet");
debugPrint(
"setup_node address $address login $login password $password useSSL $useSSL isLightWallet $isLightWallet");
// TODO: here can be ZERO! upd: no
final isSetupNode = setupNodeNative(
addressPointer,
@ -212,15 +228,14 @@ bool setupNodeSync(
return isSetupNode;
}
void startRefreshSync() => startRefreshNative();
//void startRefreshSync() => startRefreshNative();
Future<bool> connectToNode() async => connecToNodeNative() != 0;
void setRefreshFromBlockHeight({required int height}) =>
setRefreshFromBlockHeightNative(height);
void setRefreshFromBlockHeight({required int height}) => setRefreshFromBlockHeightNative(height);
void setRecoveringFromSeed({required bool isRecovery}) =>
setRecoveringFromSeedNative(_boolToInt(isRecovery));
// void setRecoveringFromSeed({required bool isRecovery}) =>
// setRecoveringFromSeedNative(_boolToInt(isRecovery));
void storeSync(int hWallet) {
calls.store(hWallet);
@ -247,17 +262,13 @@ void setPasswordSync(String password) {
void closeCurrentWallet() => closeCurrentWalletNative();
String getSecretViewKey() =>
convertUTF8ToString(pointer: getSecretViewKeyNative());
String getSecretViewKey() => convertUTF8ToString(pointer: getSecretViewKeyNative());
String getPublicViewKey() =>
convertUTF8ToString(pointer: getPublicViewKeyNative());
String getPublicViewKey() => convertUTF8ToString(pointer: getPublicViewKeyNative());
String getSecretSpendKey() =>
convertUTF8ToString(pointer: getSecretSpendKeyNative());
String getSecretSpendKey() => convertUTF8ToString(pointer: getSecretSpendKeyNative());
String getPublicSpendKey() =>
convertUTF8ToString(pointer: getPublicSpendKeyNative());
String getPublicSpendKey() => convertUTF8ToString(pointer: getPublicSpendKeyNative());
class SyncListener {
SyncListener(this.onNewBlock, this.onNewTransaction)
@ -273,36 +284,54 @@ class SyncListener {
int _lastKnownBlockHeight;
int _initialSyncHeight;
Future<int> getNodeHeightOrUpdate(int baseHeight) async {
Future<int> getNodeHeightOrUpdate(int hWallet, int baseHeight) async {
if (_cachedBlockchainHeight < baseHeight || _cachedBlockchainHeight == 0) {
_cachedBlockchainHeight = await getNodeHeight();
_cachedBlockchainHeight = await compute<int, int>(getNodeHeightSync, hWallet);
}
return _cachedBlockchainHeight;
}
void start() {
void start(ZanoWalletBase wallet, int hWallet) async {
_cachedBlockchainHeight = 0;
_lastKnownBlockHeight = 0;
_initialSyncHeight = 0;
_updateSyncInfoTimer ??=
Timer.periodic(Duration(milliseconds: 1200), (_) async {
if (isNewTransactionExist()) {
_updateSyncInfoTimer ??= Timer.periodic(Duration(milliseconds: 1200), (_) async {
/**if (isNewTransactionExist()) {
onNewTransaction?.call();
}
}*/
var syncHeight = getSyncingHeight();
///var syncHeight = getSyncingHeight();
var syncHeight = getCurrentHeight(hWallet);
if (syncHeight <= 0) {
// TODO: fix it
syncHeight = getCurrentHeight(-1);
syncHeight = getCurrentHeight(hWallet);
}
//getWalletInfo(hWallet);
final json = calls.getWalletInfo(hWallet);
final result = GetWalletInfoResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
wallet.seed = result.wiExtended.seed;
wallet.keys = ZanoWalletKeys(
privateSpendKey: result.wiExtended.spendPrivateKey,
privateViewKey: result.wiExtended.viewPrivateKey,
publicSpendKey: result.wiExtended.spendPublicKey,
publicViewKey: result.wiExtended.viewPublicKey,
);
final balance = result.wi.balances.first;
wallet.assetId = balance.assetInfo.assetId;
wallet.balance = mobx.ObservableMap.of(
{CryptoCurrency.zano: ZanoBalance(total: balance.total, unlocked: balance.unlocked)});
getTxFee(hWallet);
if (_initialSyncHeight <= 0) {
_initialSyncHeight = syncHeight;
}
final bchHeight = await getNodeHeightOrUpdate(syncHeight);
final bchHeight = await getNodeHeightOrUpdate(hWallet, syncHeight);
if (_lastKnownBlockHeight == syncHeight || syncHeight == null) {
return;
@ -326,8 +355,8 @@ class SyncListener {
void stop() => _updateSyncInfoTimer?.cancel();
}
SyncListener setListeners(void Function(int, int, double) onNewBlock,
void Function() onNewTransaction) {
SyncListener setListeners(
void Function(int, int, double) onNewBlock, void Function() onNewTransaction) {
final listener = SyncListener(onNewBlock, onNewTransaction);
/**setListenerNative();*/
return listener;
@ -346,19 +375,19 @@ bool _setupNodeSync(Map args) {
/*final socksProxyAddress = (args['socksProxyAddress'] ?? '') as String;*/
return setupNodeSync(
address: address,
login: login,
password: password,
useSSL: useSSL,
isLightWallet: isLightWallet,
/*socksProxyAddress: socksProxyAddress*/);
address: address,
login: login,
password: password,
useSSL: useSSL,
isLightWallet: isLightWallet, /*socksProxyAddress: socksProxyAddress*/
);
}
bool _isConnected(Object _) => isConnectedSync();
int _getNodeHeight(Object _) => getNodeHeightSync();
//int _getNodeHeight(Object _) => getNodeHeightSync();
void startRefresh() => startRefreshSync();
//void startRefresh() => startRefreshSync();
Future<bool> setupNode(
{required String address,
@ -380,11 +409,11 @@ Future<void> store(int hWallet) => compute<int, void>(_storeSync, 0);
Future<bool> isConnected() => compute(_isConnected, 0);
Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
//Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
Future setTrustedDaemon(bool trusted) async =>
setTrustedDaemonNative(_boolToInt(trusted));
// Future setTrustedDaemon(bool trusted) async =>
// setTrustedDaemonNative(_boolToInt(trusted));
Future<bool> trustedDaemon() async => trustedDaemonNative() != 0;

View file

@ -200,11 +200,11 @@ Future<void> _openWallet(Map<String, String> args) async => loadWallet(
bool _isWalletExist(String path) => isWalletExistSync(path: path);
void openWallet(
{required String path,
required String password,
int nettype = 0}) async =>
loadWallet(path: path, password: password, nettype: nettype);
// void openWallet(
// {required String path,
// required String password,
// int nettype = 0}) async =>
// loadWallet(path: path, password: password, nettype: nettype);
Future<void> openWalletAsync(Map<String, String> args) async =>
compute(_openWallet, args);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,19 @@
import 'package:cw_core/wallet_addresses.dart';
class NewZanoWalletAddresses extends WalletAddresses {
@override
String address;
NewZanoWalletAddresses(super.walletInfo): address = "";
@override
Future<void> init() async {
print("NewZanoWalletAddresses init");
}
@override
Future<void> updateAddressesInBox() async {
print("NewZanoWalletAddresses updateAddressesInBox");
}
}

View file

@ -0,0 +1,239 @@
import 'dart:async';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_zano/api/model/balance.dart';
import 'package:cw_zano/api/model/create_wallet_result.dart';
import 'package:cw_zano/api/zano_api.dart';
import 'package:cw_zano/zano_balance.dart';
import 'package:cw_zano/zano_transaction_history.dart';
import 'package:cw_zano/zano_transaction_info.dart';
import 'package:mobx/src/api/observable_collections.dart';
import 'package:cw_zano/api/wallet.dart' as zano_wallet;
import 'dart:convert';
import 'dart:ffi';
import 'package:cw_zano/api/signatures.dart';
import 'package:cw_zano/api/types.dart';
import 'package:ffi/ffi.dart';
import 'api/model/zano_wallet_keys.dart';
import 'new_zano_addresses_base.dart';
typedef _load_wallet = Pointer<Utf8> Function(Pointer<Utf8>, Pointer<Utf8>, Int8);
typedef _LoadWallet = Pointer<Utf8> Function(Pointer<Utf8>, Pointer<Utf8>, int);
class NewZanoWallet extends WalletBase<ZanoBalance, ZanoTransactionHistory, ZanoTransactionInfo> {
@override
SyncStatus syncStatus;
Timer? _autoSaveTimer;
static const int _autoSaveInterval = 30;
NewZanoWallet(super.walletInfo)
: balance = ObservableMap.of({CryptoCurrency.zano: ZanoBalance(total: 0, unlocked: 0)}),
walletAddresses = NewZanoWalletAddresses(walletInfo),
syncStatus = NotConnectedSyncStatus() {
transactionHistory = ZanoTransactionHistory();
}
Future<void> init() async {
print("NewZanoWallet init");
if (walletInfo.isRecovery) {
print("is recovery");
}
_autoSaveTimer =
Timer.periodic(Duration(seconds: _autoSaveInterval), (_) async => await save());
}
String getTransactionAddress(int accountIndex, int addressIndex) {
print("NewZanoWallet getTransactionAddress");
return "";
}
@override
ObservableMap<CryptoCurrency, ZanoBalance> balance;
@override
int calculateEstimatedFee(TransactionPriority priority, int? amount) {
// TODO: implement calculateEstimatedFee
throw UnimplementedError();
}
@override
Future<void> changePassword(String password) {
// TODO: implement changePassword
throw UnimplementedError();
}
@override
void close() {
// TODO: implement close
}
@override
Future<void> connectToNode({required Node node}) async {
print("NewZanoWallet connecttoNode");
try {
syncStatus = ConnectingSyncStatus();
_setupNode(address: "195.201.107.230:33336", login: "", password: "");
syncStatus = ConnectedSyncStatus();
} catch (e) {
syncStatus = FailedSyncStatus();
print("connectToNode error $e");
}
}
@override
Future<PendingTransaction> createTransaction(Object credentials) {
// TODO: implement createTransaction
throw UnimplementedError();
}
@override
Future<Map<String, ZanoTransactionInfo>> fetchTransactions() {
// TODO: implement fetchTransactions
throw UnimplementedError();
}
@override
ZanoWalletKeys get keys => ZanoWalletKeys(
privateSpendKey: "", privateViewKey: "", publicSpendKey: "", publicViewKey: "");
@override
Future<void> renameWalletFiles(String newWalletName) {
// TODO: implement renameWalletFiles
throw UnimplementedError();
}
@override
Future<void> rescan({required int height}) {
// TODO: implement rescan
throw UnimplementedError();
}
@override
Future<void> save() async {
await walletAddresses.updateAddressesInBox();
if (hWallet != null) await zano_wallet.store(hWallet!);
}
@override
// TODO: implement seed
String? seed = "Тут пока пусто";
@override
Future<void> startSync() {
// TODO: implement startSync
throw UnimplementedError();
}
@override
Future<void>? updateBalance() {
// TODO: implement updateBalance
throw UnimplementedError();
}
@override
NewZanoWalletAddresses walletAddresses;
CreateWalletResult? createWalletResult;
List<Balance>? balances;
int? hWallet;
final assetIds = <String, String>{};
final _setupNodeNative =
zanoApi.lookup<NativeFunction<setup_node>>('setup_node').asFunction<SetupNode>();
final _createWalletNative =
zanoApi.lookup<NativeFunction<create_wallet>>('create_wallet').asFunction<CreateWallet>();
final _loadWalletNative =
zanoApi.lookup<NativeFunction<_load_wallet>>('load_wallet').asFunction<_LoadWallet>();
bool _setupNode(
{required String address,
required String login,
required String password,
bool useSSL = false,
bool isLightWallet = false}) {
final addressPointer = address.toNativeUtf8();
final loginPointer = login.toNativeUtf8();
final passwordPointer = password.toNativeUtf8();
final errorMessagePointer = ''.toNativeUtf8();
print(
"setup_node address $address login $login password $password useSSL $useSSL isLightWallet $isLightWallet");
final result = _intToBool(_setupNodeNative(addressPointer, loginPointer, passwordPointer,
_boolToInt(useSSL), _boolToInt(isLightWallet), errorMessagePointer));
print("setup_node result $result");
calloc.free(addressPointer);
calloc.free(loginPointer);
calloc.free(passwordPointer);
return result;
}
String _createWalletSync(
{required String path, required String password, required String language, int nettype = 0}) {
final pathPointer = path.toNativeUtf8();
final passwordPointer = password.toNativeUtf8();
final languagePointer = language.toNativeUtf8();
final errorMessagePointer = ''.toNativeUtf8();
print("create_wallet path $path password $password language $language");
final result = _convertUTF8ToString(
pointer: _createWalletNative(
pathPointer, passwordPointer, languagePointer, nettype, errorMessagePointer));
print("create_wallet $result");
calloc.free(pathPointer);
calloc.free(passwordPointer);
calloc.free(languagePointer);
return result;
}
void createWallet({required String path, required String password}) {
final createResult = _createWalletSync(path: path, password: password, language: "");
final address = _parseResult(createResult)!;
walletAddresses.address = address;
}
String loadWallet(String path, String password) {
print('load_wallet path $path password $password');
final pathPointer = path.toNativeUtf8();
final passwordPointer = password.toNativeUtf8();
final result = _convertUTF8ToString(
pointer: _loadWalletNative(pathPointer, passwordPointer, 0),
);
print('load_wallet result $result');
return result;
}
int _boolToInt(bool value) => value ? 1 : 0;
bool _intToBool(int value) => value != 0;
String _convertUTF8ToString({required Pointer<Utf8> pointer}) {
final str = pointer.toDartString();
calloc.free(pointer);
return str;
}
// TODO: kind of stupid thing, in one method parsing json and then setting properties of a class
String? _parseResult(String result) {
final map = json.decode(result) as Map<String, dynamic>;
if (map['result'] != null) {
createWalletResult =
CreateWalletResult.fromJson(map['result'] as Map<String, dynamic>);
balances = createWalletResult!.wi.balances;
hWallet = createWalletResult!.walletId;
assetIds.clear();
for (final balance in createWalletResult!.wi.balances) {
assetIds[balance.assetInfo.assetId] = balance.assetInfo.ticker;
}
return createWalletResult!.wi.address;
}
return null;
}
}

View file

@ -27,8 +27,10 @@ class PendingZanoTransaction with PendingTransaction {
String get hex => '';
@override
String get amountFormatted => AmountConverter.amountIntToString(
String get amountFormatted {
return AmountConverter.amountIntToString(
cryptoCurrency, pendingTransactionDescription.amount);
}
@override
String get feeFormatted => AmountConverter.amountIntToString(

View file

@ -1,53 +1,23 @@
import 'package:cw_core/balance.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_core/monero_balance.dart';
import 'package:cw_zano/api/balance_list.dart';
import 'package:cw_zano/api/structs/zano_balance_row.dart';
class ZanoBalance extends Balance {
ZanoBalance(super.available, super.additional);
late int unlockedBalance;
@override
// TODO: implement formattedAdditionalBalance
String get formattedAdditionalBalance {
// TODO: fix it
return "0";
}
final int total;
final int unlocked;
ZanoBalance({required this.total, required this.unlocked}): super(unlocked, 0);
@override
// TODO: implement formattedAvailableBalance
String get formattedAvailableBalance {
// TODO: fix it
return "0";
}
String get formattedAdditionalBalance => moneroAmountToString(amount: additional);
@override
String get formattedAvailableBalance => moneroAmountToString(amount: unlocked);
@override
String get formattedFrozenBalance => total == unlocked ? '' : moneroAmountToString(amount: total - unlocked);
}
Map<CryptoCurrency, ZanoBalance> getZanoBalance() {
// TODO: fix it
return { CryptoCurrency.zano: ZanoBalance(0, 0) };
}
/*Map<CryptoCurrency, MoneroBalance> getZanoBalance({required int accountIndex}) {
final fullBalances = getZanoFullBalance(accountIndex: accountIndex);
final unlockedBalances = getZanoUnlockedBalance(accountIndex: accountIndex);
final zanoBalances = <CryptoCurrency, MoneroBalance>{};
final balancesLength = fullBalances.length;
for (int i = 0; i < balancesLength; i++) {
final assetType = fullBalances[i].getAssetType();
final fullBalance = fullBalances[i].getAmount();
final unlockedBalance = unlockedBalances[i].getAmount();
final moneroBalance = MoneroBalance(
fullBalance: fullBalance, unlockedBalance: unlockedBalance);
final currency = CryptoCurrency.fromString(assetType);
if (inactiveBalances.indexOf(currency) >= 0) {
continue;
}
zanoBalances[currency] = moneroBalance;
}
return zanoBalances;
}*/

View file

@ -1,5 +1,6 @@
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_zano/api/model/history.dart';
import 'package:cw_zano/api/structs/transaction_info_row.dart';
import 'package:cw_core/parseBoolFromString.dart';
import 'package:cw_core/transaction_direction.dart';
@ -19,7 +20,22 @@ class ZanoTransactionInfo extends TransactionInfo {
this.fee,
this.confirmations);
ZanoTransactionInfo.fromMap(Map<String, Object> map)
ZanoTransactionInfo.fromHistory(History history)
: id = history.txHash,
height = history.height,
direction = history.subtransfers.first.isIncome ? TransactionDirection.incoming :
TransactionDirection.outgoing,
date = DateTime.fromMillisecondsSinceEpoch(history.timestamp * 1000),
isPending = false,
amount = history.subtransfers.first.amount,
accountIndex = 0,
addressIndex = 0,
fee = history.fee,
confirmations = 1,
assetType = 'ZANO', // TODO: FIXIT:
recipientAddress = history.remoteAddresses.isNotEmpty ? history.remoteAddresses.first : '';
/*ZanoTransactionInfo.fromMap(Map<String, Object> map)
: id = (map['hash'] ?? '') as String,
height = (map['height'] ?? 0) as int,
direction =
@ -33,9 +49,9 @@ class ZanoTransactionInfo extends TransactionInfo {
addressIndex = map['addressIndex'] as int,
confirmations = map['confirmations'] as int,
key = getTxKey((map['hash'] ?? '') as String),
fee = map['fee'] as int? ?? 0;
fee = map['fee'] as int? ?? 0;*/
ZanoTransactionInfo.fromRow(TransactionInfoRow row)
/*ZanoTransactionInfo.fromRow(TransactionInfoRow row)
: id = row.getHash(),
height = row.blockHeight,
direction = parseTransactionDirectionFromInt(row.direction) ??
@ -48,7 +64,7 @@ class ZanoTransactionInfo extends TransactionInfo {
confirmations = row.confirmations,
key = null, //getTxKey(row.getHash()),
fee = row.fee,
assetType = row.getAssetType();
assetType = row.getAssetType();*/
final String id;
final int height;

View file

@ -1,37 +1,35 @@
import 'dart:async';
import 'dart:convert';
import 'dart:ffi';
import 'dart:io';
import 'dart:math';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_zano/api/zano_output.dart';
import 'package:cw_zano/zano_transaction_creation_credentials.dart';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_zano/zano_transaction_creation_exception.dart';
import 'package:cw_zano/zano_transaction_info.dart';
import 'package:cw_zano/zano_wallet_addresses.dart';
import 'package:cw_zano/api/calls.dart' as calls;
import 'package:cw_core/monero_wallet_utils.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_zano/api/calls.dart' as calls;
import 'package:cw_zano/api/model/destination.dart';
import 'package:cw_zano/api/model/history.dart';
import 'package:cw_zano/api/model/transfer_params.dart';
import 'package:cw_zano/api/model/zano_wallet_keys.dart';
import 'package:cw_zano/api/structs/pending_transaction.dart';
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_zano/api/transaction_history.dart'
as zano_transaction_history;
//import 'package:cw_zano/wallet.dart';
import 'package:cw_zano/api/wallet.dart' as zano_wallet;
import 'package:cw_zano/api/transaction_history.dart' as transaction_history;
import 'package:cw_zano/api/zano_output.dart';
import 'package:cw_zano/api/zano_api.dart';
import 'package:cw_zano/pending_zano_transaction.dart';
import 'package:cw_core/monero_wallet_keys.dart';
import 'package:cw_core/monero_balance.dart';
import 'package:cw_zano/zano_transaction_history.dart';
import 'package:cw_core/account.dart';
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:cw_zano/zano_balance.dart';
import 'package:cw_zano/zano_transaction_creation_credentials.dart';
import 'package:cw_zano/zano_transaction_history.dart';
import 'package:cw_zano/zano_transaction_info.dart';
import 'package:cw_zano/zano_wallet_addresses.dart';
import 'package:ffi/ffi.dart';
import 'package:mobx/mobx.dart';
part 'zano_wallet.g.dart';
@ -39,21 +37,16 @@ const moneroBlockSize = 1000;
class ZanoWallet = ZanoWalletBase with _$ZanoWallet;
abstract class ZanoWalletBase
extends WalletBase<ZanoBalance, ZanoTransactionHistory, ZanoTransactionInfo>
with Store {
ZanoWalletBase.simple({required WalletInfo walletInfo})
: balance = ObservableMap(),
_isTransactionUpdating = false,
_hasSyncAfterStartup = false,
walletAddresses = ZanoWalletAddresses(walletInfo),
syncStatus = NotConnectedSyncStatus(),
super(walletInfo) {
transactionHistory = ZanoTransactionHistory();
}
typedef _load_wallet = Pointer<Utf8> Function(Pointer<Utf8>, Pointer<Utf8>, Int8);
typedef _LoadWallet = Pointer<Utf8> Function(Pointer<Utf8>, Pointer<Utf8>, int);
ZanoWalletBase({required WalletInfo walletInfo})
: balance = ObservableMap.of({CryptoCurrency.zano: ZanoBalance(0, 0)}),
const int zanoMixin = 10;
abstract class ZanoWalletBase
extends WalletBase<ZanoBalance, ZanoTransactionHistory, ZanoTransactionInfo> with Store {
ZanoWalletBase(WalletInfo walletInfo)
: balance = ObservableMap.of({CryptoCurrency.zano: ZanoBalance(total: 0, unlocked: 0)}),
_isTransactionUpdating = false,
_hasSyncAfterStartup = false,
walletAddresses = ZanoWalletAddresses(walletInfo),
@ -70,6 +63,9 @@ abstract class ZanoWalletBase
});*/
}
List<History> history = [];
String assetId = '';
static const int _autoSaveInterval = 30;
@override
@ -84,20 +80,11 @@ abstract class ZanoWalletBase
ObservableMap<CryptoCurrency, ZanoBalance> balance;
@override
String get seed {
// TODO: fix it
//return calls.seed(hWallet);
return "test";
/**zano_wallet.getSeed();*/
}
String seed = '';
@override
// TODO: ?? why monero
MoneroWalletKeys get keys => MoneroWalletKeys(
privateSpendKey: zano_wallet.getSecretSpendKey(),
privateViewKey: zano_wallet.getSecretViewKey(),
publicSpendKey: zano_wallet.getPublicSpendKey(),
publicViewKey: zano_wallet.getPublicViewKey());
ZanoWalletKeys keys = ZanoWalletKeys(
privateSpendKey: '', privateViewKey: '', publicSpendKey: '', publicViewKey: '');
zano_wallet.SyncListener? _listener;
/**ReactionDisposer? _onAccountChangeReaction;*/
@ -115,21 +102,20 @@ abstract class ZanoWalletBase
Future<void> init() async {
await walletAddresses.init();
balance
.addAll(getZanoBalance(/**accountIndex: walletAddresses.account?.id ?? 0*/));
///balance.addAll(getZanoBalance(/**accountIndex: walletAddresses.account?.id ?? 0*/));
_setListeners();
await updateTransactions();
if (walletInfo.isRecovery) {
zano_wallet.setRecoveringFromSeed(isRecovery: walletInfo.isRecovery);
///zano_wallet.setRecoveringFromSeed(isRecovery: walletInfo.isRecovery);
if (zano_wallet.getCurrentHeight(hWallet) <= 1) {
zano_wallet.setRefreshFromBlockHeight(height: walletInfo.restoreHeight);
}
}
_autoSaveTimer = Timer.periodic(
Duration(seconds: _autoSaveInterval), (_) async => await save());
_autoSaveTimer =
Timer.periodic(Duration(seconds: _autoSaveInterval), (_) async => await save());
}
@override
@ -155,7 +141,7 @@ abstract class ZanoWalletBase
/*socksProxyAddress: node.socksProxyAddress*/
);
zano_wallet.setTrustedDaemon(node.trusted);
//zano_wallet.setTrustedDaemon(node.trusted);
syncStatus = ConnectedSyncStatus();
} catch (e) {
syncStatus = FailedSyncStatus();
@ -171,9 +157,10 @@ abstract class ZanoWalletBase
try {
syncStatus = AttemptingSyncStatus();
zano_wallet.startRefresh();
//zano_wallet.startRefresh();
print("start refresh");
_setListeners();
_listener?.start();
_listener?.start(this, hWallet);
} catch (e) {
syncStatus = FailedSyncStatus();
print(e);
@ -183,7 +170,38 @@ abstract class ZanoWalletBase
@override
Future<PendingTransaction> createTransaction(Object credentials) async {
final _credentials = credentials as ZanoTransactionCreationCredentials;
final creds = credentials as ZanoTransactionCreationCredentials;
final output = creds.outputs.first;
final address = output.isParsedAddress && (output.extractedAddress?.isNotEmpty ?? false)
? output.extractedAddress!
: output.address;
final amount = output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.');
final int? formattedAmount = output.sendAll ? null : output.formattedCryptoAmount;
final fee = calculateEstimatedFee(creds.priority);
// final result = await calls.transfer(
// hWallet,
// TransferParams(
// destinations: [
// Destination(
// amount: amount!,
// address: address,
// assetId: assetId,
// )
// ],
// fee: fee,
// mixin: zanoMixin,
// paymentId: '', // TODO: fixit
// comment: output.note ?? '',
// pushPayer: false,
// hideReceiver: false,
// ));
int iAmount = (double.parse(amount!) * pow(10, 12)).toInt();
final description = PendingTransactionDescription(
amount: iAmount, fee: fee, hash: 'fade', pointerAddress: 0);
final transaction = PendingZanoTransaction(description, CryptoCurrency.zano);
return transaction;
/*final _credentials = credentials as ZanoTransactionCreationCredentials;
final outputs = _credentials.outputs;
final hasMultiDestination = outputs.length > 1;
final assetType =
@ -249,29 +267,12 @@ abstract class ZanoWalletBase
priorityRaw: _credentials.priority.serialize());
}
return PendingZanoTransaction(pendingTransactionDescription, assetType);
return PendingZanoTransaction(pendingTransactionDescription, assetType);*/
}
@override
int calculateEstimatedFee(TransactionPriority priority, int? amount) {
// FIXME: hardcoded value;
if (priority is MoneroTransactionPriority) {
switch (priority) {
case MoneroTransactionPriority.slow:
return 24590000;
case MoneroTransactionPriority.automatic:
return 123050000;
case MoneroTransactionPriority.medium:
return 245029999;
case MoneroTransactionPriority.fast:
return 614530000;
case MoneroTransactionPriority.fastest:
return 26021600000;
}
}
return 0;
int calculateEstimatedFee(TransactionPriority priority, [int? amount = null]) {
return calls.getCurrentTxFee(priority.raw);
}
@override
@ -310,7 +311,7 @@ abstract class ZanoWalletBase
zano_wallet.setPasswordSync(password);
}
Future<int> getNodeHeight() async => zano_wallet.getNodeHeight();
//Future<int> getNodeHeight() async => zano_wallet.getNodeHeight();
Future<bool> isConnected() async => zano_wallet.isConnected();
@ -334,18 +335,37 @@ abstract class ZanoWalletBase
}
String getTransactionAddress(int accountIndex, int addressIndex) =>
zano_wallet.getAddress(
accountIndex: accountIndex, addressIndex: addressIndex);
zano_wallet.getAddress(accountIndex: accountIndex, addressIndex: addressIndex);
Future<void> _refreshTransactions() async {
final result = await calls.getRecentTxsAndInfo(hWallet: hWallet, offset: 0, count: 30);
final map = jsonDecode(result);
if (map == null || map["result"] == null || map["result"]["result"] == null) {
return;
}
if (map["result"]["result"]["transfers"] != null)
history = (map["result"]["result"]["transfers"] as List<dynamic>)
.map((e) => History.fromJson(e as Map<String, dynamic>))
.toList();
}
@override
Future<Map<String, ZanoTransactionInfo>> fetchTransactions() async {
zano_transaction_history.refreshTransactions();
return _getAllTransactions(null)
//zano_transaction_history.refreshTransactions();
await _refreshTransactions();
return history
.map<ZanoTransactionInfo>((history) => ZanoTransactionInfo.fromHistory(history))
.fold<Map<String, ZanoTransactionInfo>>(<String, ZanoTransactionInfo>{},
(Map<String, ZanoTransactionInfo> acc, ZanoTransactionInfo tx) {
acc[tx.id] = tx;
return acc;
});
// return _getAllTransactions(null)
// .fold<Map<String, ZanoTransactionInfo>>(<String, ZanoTransactionInfo>{},
// (Map<String, ZanoTransactionInfo> acc, ZanoTransactionInfo tx) {
// acc[tx.id] = tx;
// return acc;
// });
}
Future<void> updateTransactions() async {
@ -365,11 +385,11 @@ abstract class ZanoWalletBase
}
}
List<ZanoTransactionInfo> _getAllTransactions(dynamic _) =>
zano_transaction_history
.getAllTransations()
.map((row) => ZanoTransactionInfo.fromRow(row))
.toList();
// List<ZanoTransactionInfo> _getAllTransactions(dynamic _) =>
// zano_transaction_history
// .getAllTransations()
// .map((row) => ZanoTransactionInfo.fromRow(row))
// .toList();
void _setListeners() {
_listener?.stop();
@ -385,36 +405,39 @@ abstract class ZanoWalletBase
if (currentHeight <= 1) {
final height = _getHeightByDate(walletInfo.date);
zano_wallet.setRecoveringFromSeed(isRecovery: true);
///zano_wallet.setRecoveringFromSeed(isRecovery: true);
zano_wallet.setRefreshFromBlockHeight(height: height);
}
}
int _getHeightDistance(DateTime date) {
final distance =
DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch;
final daysTmp = (distance / 86400).round();
final days = daysTmp < 1 ? 1 : daysTmp;
// int _getHeightDistance(DateTime date) {
// final distance =
// DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch;
// final daysTmp = (distance / 86400).round();
// final days = daysTmp < 1 ? 1 : daysTmp;
return days * 1000;
}
// return days * 1000;
// }
int _getHeightByDate(DateTime date) {
final nodeHeight = zano_wallet.getNodeHeightSync();
final heightDistance = _getHeightDistance(date);
// TODO: !!! 12/10 commented
return 0;
// final nodeHeight = zano_wallet.getNodeHeightSync();
// final heightDistance = _getHeightDistance(date);
if (nodeHeight <= 0) {
return 0;
}
// if (nodeHeight <= 0) {
// return 0;
// }
return nodeHeight - heightDistance;
// return nodeHeight - heightDistance;
}
void _askForUpdateBalance() =>
balance.addAll(getZanoBalance());
void _askForUpdateBalance() {
print("ask for update balance");
//balance.addAll(getZanoBalance());
}
Future<void> _askForUpdateTransactionHistory() async =>
await updateTransactions();
Future<void> _askForUpdateTransactionHistory() async => await updateTransactions();
void _onNewBlock(int height, int blocksLeft, double ptc) async {
try {
@ -455,4 +478,24 @@ abstract class ZanoWalletBase
print(e.toString());
}
}
final _loadWalletNative =
zanoApi.lookup<NativeFunction<_load_wallet>>('load_wallet').asFunction<_LoadWallet>();
String loadWallet(String path, String password) {
print('load_wallet path $path password $password');
final pathPointer = path.toNativeUtf8();
final passwordPointer = password.toNativeUtf8();
final result = _convertUTF8ToString(
pointer: _loadWalletNative(pathPointer, passwordPointer, 0),
);
print('load_wallet result $result');
return result;
}
String _convertUTF8ToString({required Pointer<Utf8> pointer}) {
final str = pointer.toDartString();
calloc.free(pointer);
return str;
}
}

View file

@ -1,8 +1,13 @@
import 'dart:convert';
import 'dart:io';
import 'package:collection/collection.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/monero_wallet_utils.dart';
import 'package:cw_zano/api/model/create_wallet_result.dart';
import 'package:cw_zano/new_zano_wallet.dart';
import 'package:cw_zano/zano_balance.dart';
import 'package:hive/hive.dart';
import 'package:cw_zano/api/wallet_manager.dart' as zano_wallet_manager;
import 'package:cw_zano/api/wallet.dart' as zano_wallet;
@ -14,6 +19,7 @@ import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart';
class ZanoNewWalletCredentials extends WalletCredentials {
ZanoNewWalletCredentials({required String name, String? password})
@ -22,10 +28,7 @@ class ZanoNewWalletCredentials extends WalletCredentials {
class ZanoRestoreWalletFromSeedCredentials extends WalletCredentials {
ZanoRestoreWalletFromSeedCredentials(
{required String name,
required String password,
required int height,
required this.mnemonic})
{required String name, required String password, required int height, required this.mnemonic})
: super(name: name, password: password, height: height);
final String mnemonic;
@ -53,10 +56,8 @@ class ZanoRestoreWalletFromKeysCredentials extends WalletCredentials {
final String spendKey;
}
class ZanoWalletService extends WalletService<
ZanoNewWalletCredentials,
ZanoRestoreWalletFromSeedCredentials,
ZanoRestoreWalletFromKeysCredentials> {
class ZanoWalletService extends WalletService<ZanoNewWalletCredentials,
ZanoRestoreWalletFromSeedCredentials, ZanoRestoreWalletFromKeysCredentials> {
ZanoWalletService(this.walletInfoSource);
final Box<WalletInfo> walletInfoSource;
@ -69,18 +70,38 @@ class ZanoWalletService extends WalletService<
@override
WalletType getType() => WalletType.zano;
// @override
// Future<ZanoWallet> create(WalletCredentials credentials) async {
// try {
// final wallet = ZanoWallet(credentials.walletInfo!);
// wallet.connectToNode(node: Node()); // TODO: Node() ???
// //wallet.setupNode(address: "195.201.107.230:33336", login: "", password: "");
// final path = await pathForWallet(name: credentials.name, type: getType());
// wallet.createWallet(path: path, password: credentials.password!);
// return wallet;
// } catch (e) {
// print("ZanoWalletService.create error $e");
// rethrow;
// }
// }
@override
Future<ZanoWallet> create(ZanoNewWalletCredentials credentials) async {
Future<ZanoWallet> create(WalletCredentials credentials) async {
try {
final wallet = ZanoWallet.simple(walletInfo: credentials.walletInfo!);
wallet.connectToNode(node: Node());
final wallet = ZanoWallet(credentials.walletInfo!);
await wallet.connectToNode(node: Node());
final path = await pathForWallet(name: credentials.name, type: getType());
final result = await zano_wallet_manager.createWallet(
language: "", path: path, password: credentials.password!);
hWallet = -1;
wallet.hWallet = hWallet;
// TODO: remove it
calls.store(hWallet);
print("create wallet result $result");
final map = json.decode(result) as Map<String, dynamic>;
if (map['result'] != null) {
final createWalletResult =
CreateWalletResult.fromJson(map['result'] as Map<String, dynamic>);
_parseCreateWalletResult(createWalletResult, wallet);
}
// TODO: remove it TODO why?
await calls.store(hWallet);
await wallet.init();
return wallet;
} catch (e) {
@ -111,40 +132,39 @@ class ZanoWalletService extends WalletService<
await repairOldAndroidWallet(name);
}
await zano_wallet_manager
.openWalletAsync({'path': path, 'password': password});
final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(name, getType()))!;
final wallet = ZanoWallet(walletInfo: walletInfo);
/*final isValid = wallet.walletAddresses.validate();
if (!isValid) {
await restoreOrResetWalletFiles(name);
wallet.close();
return openWallet(name, password);
}*/
final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
final wallet = ZanoWallet(walletInfo);
await wallet.connectToNode(node: Node());
final result = wallet.loadWallet(path, password);
print("load wallet result $result");
final map = json.decode(result) as Map<String, dynamic>;
if (map['result'] != null) {
final createWalletResult =
CreateWalletResult.fromJson(map['result'] as Map<String, dynamic>);
_parseCreateWalletResult(createWalletResult, wallet);
}
await calls.store(hWallet);
await wallet.init();
return wallet;
} catch (e) {
// TODO: Implement Exception for wallet list service.
if ((e.toString().contains('bad_alloc') ||
(e is WalletOpeningException &&
(e.message == 'std::bad_alloc' ||
e.message.contains('bad_alloc')))) ||
(e.toString().contains('does not correspond') ||
(e is WalletOpeningException &&
e.message.contains('does not correspond')))) {
await restoreOrResetWalletFiles(name);
return openWallet(name, password);
}
rethrow;
}
}
void _parseCreateWalletResult(CreateWalletResult result, ZanoWallet wallet) {
hWallet = result.walletId;
wallet.hWallet = hWallet;
wallet.walletAddresses.address = result.wi.address;
final balance = result.wi.balances.first;
wallet.assetId = balance.assetInfo.assetId;
wallet.balance = ObservableMap.of(
{CryptoCurrency.zano: ZanoBalance(total: balance.total, unlocked: balance.unlocked)});
if (result.recentHistory.history != null) {
wallet.history = result.recentHistory.history!;
}
}
@override
Future<void> remove(String wallet) async {
final path = await pathForWalletDir(name: wallet, type: getType());
@ -161,11 +181,10 @@ class ZanoWalletService extends WalletService<
}
@override
Future<void> rename(
String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values.firstWhere(
(info) => info.id == WalletBase.idFor(currentName, getType()));
final currentWallet = ZanoWallet(walletInfo: currentWalletInfo);
Future<void> rename(String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
final currentWallet = ZanoWallet(currentWalletInfo);
await currentWallet.renameWalletFiles(newName);
@ -177,8 +196,7 @@ class ZanoWalletService extends WalletService<
}
@override
Future<ZanoWallet> restoreFromKeys(
ZanoRestoreWalletFromKeysCredentials credentials) async {
Future<ZanoWallet> restoreFromKeys(ZanoRestoreWalletFromKeysCredentials credentials) async {
try {
final path = await pathForWallet(name: credentials.name, type: getType());
await zano_wallet_manager.restoreFromKeys(
@ -189,7 +207,7 @@ class ZanoWalletService extends WalletService<
address: credentials.address,
viewKey: credentials.viewKey,
spendKey: credentials.spendKey);
final wallet = ZanoWallet(walletInfo: credentials.walletInfo!);
final wallet = ZanoWallet(credentials.walletInfo!);
await wallet.init();
return wallet;
@ -201,18 +219,21 @@ class ZanoWalletService extends WalletService<
}
@override
Future<ZanoWallet> restoreFromSeed(
ZanoRestoreWalletFromSeedCredentials credentials) async {
Future<ZanoWallet> restoreFromSeed(ZanoRestoreWalletFromSeedCredentials credentials) async {
try {
final wallet = ZanoWallet(credentials.walletInfo!);
await wallet.connectToNode(node: Node());
final path = await pathForWallet(name: credentials.name, type: getType());
await zano_wallet_manager.restoreFromSeed(
path: path,
password: credentials.password!,
seed: credentials.mnemonic,
restoreHeight: credentials.height!);
final wallet = ZanoWallet(walletInfo: credentials.walletInfo!);
final result = calls.restoreWalletFromSeed(path, credentials.password!, credentials.mnemonic);
print('restore wallet from seed result $result');
final map = json.decode(result) as Map<String, dynamic>;
if (map['result'] != null) {
final createWalletResult =
CreateWalletResult.fromJson(map['result'] as Map<String, dynamic>);
_parseCreateWalletResult(createWalletResult, wallet);
}
await calls.store(hWallet);
await wallet.init();
return wallet;
} catch (e) {
// TODO: Implement Exception for wallet list service.
@ -227,16 +248,14 @@ class ZanoWalletService extends WalletService<
return;
}
final oldAndroidWalletDirPath =
await outdatedAndroidPathForWalletDir(name: name);
final oldAndroidWalletDirPath = await outdatedAndroidPathForWalletDir(name: name);
final dir = Directory(oldAndroidWalletDirPath);
if (!dir.existsSync()) {
return;
}
final newWalletDirPath =
await pathForWalletDir(name: name, type: getType());
final newWalletDirPath = await pathForWalletDir(name: name, type: getType());
dir.listSync().forEach((f) {
final file = File(f.path);

View file

@ -239,6 +239,8 @@ class AddressValidator extends TextValidator {
return [64];
case CryptoCurrency.btcln:
return null;
case CryptoCurrency.zano:
return [97];
default:
return [];
}

View file

@ -211,6 +211,8 @@ class WalletRestorePage extends BasePage {
final seedWords =
walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.text.split(' ');
if (walletRestoreViewModel.type == WalletType.zano) return true;
if ((walletRestoreViewModel.type == WalletType.monero ||
walletRestoreViewModel.type == WalletType.haven) &&
seedWords.length != WalletRestoreViewModelBase.moneroSeedMnemonicLength) {

View file

@ -258,8 +258,8 @@ abstract class OutputBase with Store {
break;
case WalletType.dummy:
case WalletType.zano:
// TODO: enter correct values
throw UnimplementedError();
maximumFractionDigits = 12;
break;
default:
break;
}

View file

@ -9,7 +9,7 @@ import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cw_zano/api/calls.dart' as calls;
import 'package:cw_zano/api/model/balance.dart';
import 'package:cw_zano/api/model/load_wallet_result.dart';
import 'package:cw_zano/api/model/create_wallet_result.dart';
import 'package:cw_zano/api/wallet.dart' as zano_wallet;
import 'package:cw_zano/api/wallet_manager.dart' as zano_wallet_manager;
import 'package:cw_zano/zano_wallet_service.dart';
@ -28,24 +28,21 @@ Future<void> main() async {
/// A callback that is invoked when an unhandled error occurs in the root
/// isolate.
PlatformDispatcher.instance.onError = (error, stack) {
ExceptionHandler.onError(
FlutterErrorDetails(exception: error, stack: stack));
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
return true;
};
await setup();
runApp(App());
}, (error, stackTrace) async {
ExceptionHandler.onError(
FlutterErrorDetails(exception: error, stack: stackTrace));
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
});
}
final getIt = GetIt.instance;
Future<void> setup() async {
getIt.registerFactory<KeyService>(
() => KeyService(getIt.get<FlutterSecureStorage>()));
getIt.registerFactory<KeyService>(() => KeyService(getIt.get<FlutterSecureStorage>()));
}
class App extends StatefulWidget {
@ -79,7 +76,7 @@ class _AppState extends State<App> {
}
int hWallet = 0;
CreateLoadRestoreWalletResult? lwr;
CreateWalletResult? lwr;
List<Balance> balances = [];
String seed = '', version = '';
final assetIds = <String, String>{};
@ -107,11 +104,9 @@ Future<String?> create(String name) async {
final keyService = KeyService(FlutterSecureStorage());
final password = generateWalletPassword();
credentials.password = password;
await keyService.saveWalletPassword(
password: password, walletName: credentials.name);
await keyService.saveWalletPassword(password: password, walletName: credentials.name);
debugPrint('path $path password $password');
final result = zano_wallet_manager.createWalletSync(
path: path, password: password, language: '');
final result = zano_wallet_manager.createWalletSync(path: path, password: password, language: '');
debugPrint('create result $result');
return _parseResult(result);
}
@ -122,8 +117,7 @@ Future<String?> connect(String name) async {
final path = await pathForWallet(name: name, type: WalletType.zano);
final credentials = ZanoNewWalletCredentials(name: name);
final keyService = KeyService(FlutterSecureStorage());
final password =
await keyService.getWalletPassword(walletName: credentials.name);
final password = await keyService.getWalletPassword(walletName: credentials.name);
debugPrint('path $path password $password');
final result = await calls.loadWallet(path, password, 0);
return _parseResult(result);
@ -137,8 +131,7 @@ Future<String?> restore(String name, String seed) async {
final keyService = KeyService(FlutterSecureStorage());
final password = generateWalletPassword();
credentials.password = password;
await keyService.saveWalletPassword(
password: password, walletName: credentials.name);
await keyService.saveWalletPassword(password: password, walletName: credentials.name);
debugPrint('path $path password $password');
var result = calls.restoreWalletFromSeed(path, password, seed);
debugPrint('restore result $result');
@ -148,8 +141,8 @@ Future<String?> restore(String name, String seed) async {
String? _parseResult(String result) {
final map = json.decode(result) as Map<String, dynamic>;
if (map['result'] != null) {
lwr = CreateLoadRestoreWalletResult.fromJson(map['result'] as Map<String, dynamic>);
if (map['result'] != null) {
lwr = CreateWalletResult.fromJson(map['result'] as Map<String, dynamic>);
balances = lwr!.wi.balances;
hWallet = lwr!.walletId;
assetIds.clear();
@ -204,14 +197,12 @@ class _DisconnectedWidgetState extends State<DisconnectedWidget> {
child: Column(
children: [
TextField(
controller: _name,
decoration: InputDecoration(labelText: 'Wallet name')),
controller: _name, decoration: InputDecoration(labelText: 'Wallet name')),
TextButton(
child: Text('Connect and Open Wallet'),
onPressed: () async {
//setState(() => _loading = true);
final preferences =
await SharedPreferences.getInstance();
final preferences = await SharedPreferences.getInstance();
await preferences.setString(walletName, _name.text);
final result = await connect(_name.text);
//setState(() => _loading = false);
@ -232,8 +223,7 @@ class _DisconnectedWidgetState extends State<DisconnectedWidget> {
child: Text('Create and Open Wallet'),
onPressed: () async {
//setState(() => _loading = true);
final preferences =
await SharedPreferences.getInstance();
final preferences = await SharedPreferences.getInstance();
await preferences.setString(walletName, _name.text);
final result = await create(_name.text);
//setState(() => _loading = false);
@ -251,13 +241,11 @@ class _DisconnectedWidgetState extends State<DisconnectedWidget> {
height: 16,
),
TextField(
controller: _seed,
decoration: InputDecoration(labelText: 'Wallet seed')),
controller: _seed, decoration: InputDecoration(labelText: 'Wallet seed')),
TextButton(
child: Text('Restore from seed'),
onPressed: () async {
final preferences =
await SharedPreferences.getInstance();
final preferences = await SharedPreferences.getInstance();
await preferences.setString(walletName, _name.text);
final result = await restore(_name.text, _seed.text);
if (result != null) {

View file

@ -1,3 +1,4 @@
import 'package:cw_zano/new_zano_wallet.dart';
import 'package:mobx/mobx.dart';
import 'package:flutter/foundation.dart';
import 'package:cw_core/wallet_credentials.dart';