whitelists

This commit is contained in:
leo 2024-04-06 10:03:11 +00:00
parent 42731fcdcb
commit 89b572cae2
6 changed files with 174 additions and 73 deletions

View file

@ -56,7 +56,8 @@ typedef _stringFunction = Pointer<Utf8> Function();
class ApiCalls { class ApiCalls {
static String _convertUTF8ToString({required Pointer<Utf8> pointer}) { static String _convertUTF8ToString({required Pointer<Utf8> pointer}) {
final str = pointer.toDartStringAllowingMalformed(); final str = pointer.toDartString();
//final str = pointer.toDartStringAllowingMalformed();
calloc.free(pointer); calloc.free(pointer);
return str; return str;
} }

View file

@ -14,6 +14,8 @@ class Balance {
required this.total, required this.total,
required this.unlocked}); required this.unlocked});
String get assetId => assetInfo.assetId;
@override @override
String toString() => '$assetInfo: $total/$unlocked'; String toString() => '$assetInfo: $total/$unlocked';

View file

@ -19,18 +19,20 @@ class ZanoAsset extends CryptoCurrency with HiveObjectMixin {
bool _enabled; bool _enabled;
@HiveField(5) @HiveField(5)
final String? iconPath; final String? iconPath;
// @HiveField(6)
// final String? tag;
@HiveField(6) @HiveField(6)
final String? tag;
@HiveField(7)
final String owner; final String owner;
@HiveField(8) @HiveField(7)
final String metaInfo; final String metaInfo;
@HiveField(9) @HiveField(8)
final int currentSupply; final int currentSupply;
@HiveField(10) @HiveField(9)
final bool hiddenSupply; final bool hiddenSupply;
@HiveField(11) @HiveField(10)
final int totalMaxSupply; final int totalMaxSupply;
@HiveField(11)
final bool isInGlobalWhitelist;
bool get enabled => _enabled; bool get enabled => _enabled;
@ -43,45 +45,47 @@ class ZanoAsset extends CryptoCurrency with HiveObjectMixin {
this.decimalPoint = ZanoFormatter.defaultDecimalPoint, this.decimalPoint = ZanoFormatter.defaultDecimalPoint,
bool enabled = false, bool enabled = false,
this.iconPath, this.iconPath,
this.tag, //this.tag,
this.owner = defaultOwner, this.owner = defaultOwner,
this.metaInfo = '', this.metaInfo = '',
this.currentSupply = 0, this.currentSupply = 0,
this.hiddenSupply = false, this.hiddenSupply = false,
this.totalMaxSupply = 0, this.totalMaxSupply = 0,
this.isInGlobalWhitelist = false,
}) : _enabled = enabled, }) : _enabled = enabled,
super( super(
name: fullName, name: fullName,
title: ticker.toUpperCase(), title: ticker.toUpperCase(),
fullName: fullName, fullName: fullName,
tag: tag, tag: 'ZANO',
iconPath: iconPath, iconPath: iconPath,
decimals: decimalPoint, decimals: decimalPoint,
); );
ZanoAsset.copyWith(ZanoAsset other, String? icon, String? tag, {String? assetId, bool enabled = false}) ZanoAsset.copyWith(ZanoAsset other, String? icon, /*String? tag,*/ {String? assetId, bool enabled = false})
: this.fullName = other.fullName, : this.fullName = other.fullName,
this.ticker = other.ticker, this.ticker = other.ticker,
this.assetId = assetId ?? other.assetId, this.assetId = assetId ?? other.assetId,
this.decimalPoint = other.decimalPoint, this.decimalPoint = other.decimalPoint,
this._enabled = enabled || other.enabled, this._enabled = enabled || other.enabled,
this.tag = tag, //this.tag = tag,
this.iconPath = icon, this.iconPath = icon,
this.currentSupply = other.currentSupply, this.currentSupply = other.currentSupply,
this.hiddenSupply = other.hiddenSupply, this.hiddenSupply = other.hiddenSupply,
this.metaInfo = other.metaInfo, this.metaInfo = other.metaInfo,
this.owner = other.owner, this.owner = other.owner,
this.totalMaxSupply = other.totalMaxSupply, this.totalMaxSupply = other.totalMaxSupply,
this.isInGlobalWhitelist = other.isInGlobalWhitelist,
super( super(
name: other.name, name: other.name,
title: other.ticker.toUpperCase(), title: other.ticker.toUpperCase(),
fullName: other.name, fullName: other.name,
tag: tag, tag: 'ZANO',
iconPath: icon, iconPath: icon,
decimals: other.decimalPoint, decimals: other.decimalPoint,
); );
factory ZanoAsset.fromJson(Map<String, dynamic> json) => ZanoAsset( factory ZanoAsset.fromJson(Map<String, dynamic> json, {bool isInGlobalWhitelist = false}) => ZanoAsset(
assetId: json['asset_id'] as String? ?? '', assetId: json['asset_id'] as String? ?? '',
currentSupply: json['current_supply'] as int? ?? 0, currentSupply: json['current_supply'] as int? ?? 0,
decimalPoint: json['decimal_point'] as int? ?? ZanoFormatter.defaultDecimalPoint, decimalPoint: json['decimal_point'] as int? ?? ZanoFormatter.defaultDecimalPoint,
@ -91,9 +95,10 @@ class ZanoAsset extends CryptoCurrency with HiveObjectMixin {
owner: json['owner'] as String? ?? '', owner: json['owner'] as String? ?? '',
ticker: json['ticker'] as String? ?? '', ticker: json['ticker'] as String? ?? '',
totalMaxSupply: json['total_max_supply'] as int? ?? 0, totalMaxSupply: json['total_max_supply'] as int? ?? 0,
isInGlobalWhitelist: isInGlobalWhitelist,
); );
static const typeId = ZANO_ASSET_TYPE_ID; static const typeId = ZANO_ASSET_TYPE_ID;
static const zanoAssetsBoxName = 'zanoAssetsBox'; static const zanoAssetsBoxName = 'ZanoAssetsBox123'; // TODO: change to normal name
static const defaultOwner = '0000000000000000000000000000000000000000000000000000000000000000'; static const defaultOwner = '0000000000000000000000000000000000000000000000000000000000000000';
} }

View file

@ -5,14 +5,13 @@ class ZanoBalance extends Balance {
final int total; final int total;
final int unlocked; final int unlocked;
final int decimalPoint; final int decimalPoint;
ZanoBalance({required this.total, required this.unlocked, required this.decimalPoint}) : super(unlocked, total - unlocked); ZanoBalance({required this.total, required this.unlocked, this.decimalPoint = ZanoFormatter.defaultDecimalPoint}) : super(unlocked, total - unlocked);
ZanoBalance.empty({this.decimalPoint = ZanoFormatter.defaultDecimalPoint}): total = 0, unlocked = 0, super(0, 0);
@override @override
String get formattedAdditionalBalance => ZanoFormatter.intAmountToString(total - unlocked, decimalPoint); String get formattedAdditionalBalance => ZanoFormatter.intAmountToString(total - unlocked, decimalPoint);
@override @override
String get formattedAvailableBalance => ZanoFormatter.intAmountToString(unlocked, decimalPoint); String get formattedAvailableBalance => ZanoFormatter.intAmountToString(unlocked, decimalPoint);
// @override
// String get formattedFrozenBalance => '';
} }

View file

@ -12,6 +12,7 @@ import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_zano/api/model/balance.dart';
import 'package:cw_zano/api/model/create_wallet_result.dart'; import 'package:cw_zano/api/model/create_wallet_result.dart';
import 'package:cw_zano/api/model/destination.dart'; import 'package:cw_zano/api/model/destination.dart';
import 'package:cw_zano/api/model/get_wallet_status_result.dart'; import 'package:cw_zano/api/model/get_wallet_status_result.dart';
@ -31,6 +32,7 @@ import 'package:cw_zano/zano_wallet_service.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:collection/collection.dart';
part 'zano_wallet.g.dart'; part 'zano_wallet.g.dart';
@ -59,6 +61,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
static const String zanoAssetId = 'd6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a'; static const String zanoAssetId = 'd6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a';
late final Box<ZanoAsset> zanoAssetsBox; late final Box<ZanoAsset> zanoAssetsBox;
List<ZanoAsset> whitelists = [];
List<ZanoAsset> get zanoAssets => zanoAssetsBox.values.toList(); List<ZanoAsset> get zanoAssets => zanoAssetsBox.values.toList();
// final Map<String, ZanoAsset> zanoAssets = {}; // final Map<String, ZanoAsset> zanoAssets = {};
@ -74,7 +77,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
Timer? _autoSaveTimer; Timer? _autoSaveTimer;
ZanoWalletBase(WalletInfo walletInfo) ZanoWalletBase(WalletInfo walletInfo)
: balance = ObservableMap.of({CryptoCurrency.zano: ZanoBalance(total: 0, unlocked: 0, decimalPoint: ZanoFormatter.defaultDecimalPoint)}), : balance = ObservableMap.of({CryptoCurrency.zano: ZanoBalance.empty()}),
_isTransactionUpdating = false, _isTransactionUpdating = false,
_hasSyncAfterStartup = false, _hasSyncAfterStartup = false,
walletAddresses = ZanoWalletAddresses(walletInfo), walletAddresses = ZanoWalletAddresses(walletInfo),
@ -137,15 +140,16 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
static void _parseCreateWalletResult(CreateWalletResult result, ZanoWallet wallet) { static void _parseCreateWalletResult(CreateWalletResult result, ZanoWallet wallet) {
wallet.hWallet = result.walletId; wallet.hWallet = result.walletId;
_info('setting hWallet = ${result.walletId}');
wallet.walletAddresses.address = result.wi.address; wallet.walletAddresses.address = result.wi.address;
for (final item in result.wi.balances) { for (final item in result.wi.balances) {
if (item.assetInfo.ticker == 'ZANO') { if (item.assetInfo.ticker == 'ZANO') {
wallet.balance[CryptoCurrency.zano] = ZanoBalance( wallet.balance[CryptoCurrency.zano] = ZanoBalance(
total: item.total, total: item.total,
unlocked: item.unlocked, unlocked: item.unlocked,
decimalPoint: ZanoFormatter.defaultDecimalPoint,
); );
} else { } else {
// TODO: here will be always empty!
for (final asset in wallet.balance.keys) { for (final asset in wallet.balance.keys) {
if (asset is ZanoAsset && asset.assetId == item.assetInfo.assetId) { if (asset is ZanoAsset && asset.assetId == item.assetInfo.assetId) {
wallet.balance[asset] = ZanoBalance( wallet.balance[asset] = ZanoBalance(
@ -306,7 +310,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
print( print(
'assets in box total: ${zanoAssetsBox.length} ${zanoAssetsBox.values} active: ${zanoAssetsBox.values.where((element) => element.enabled).length} ${zanoAssetsBox.values.where((element) => element.enabled)}'); 'assets in box total: ${zanoAssetsBox.length} ${zanoAssetsBox.values} active: ${zanoAssetsBox.values.where((element) => element.enabled).length} ${zanoAssetsBox.values.where((element) => element.enabled)}');
for (final asset in zanoAssetsBox.values) { for (final asset in zanoAssetsBox.values) {
if (asset.enabled) balance[asset] = ZanoBalance(total: 0, unlocked: 0, decimalPoint: asset.decimalPoint); if (asset.enabled) balance[asset] = ZanoBalance.empty(decimalPoint: asset.decimalPoint);
} }
await walletAddresses.init(); await walletAddresses.init();
await walletAddresses.updateAddress(address); await walletAddresses.updateAddress(address);
@ -392,7 +396,65 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
publicViewKey: walletInfo.wiExtended.viewPublicKey, publicViewKey: walletInfo.wiExtended.viewPublicKey,
); );
final whitelists = await getAssetsWhitelist(); bool areSetsEqual<T>(Set<T> set1, Set<T> set2) => set1.length == set2.length && set1.every(set2.contains);
Set<String> getSetFromWhitelist(List<ZanoAsset> whitelist, bool isInGlobalWhitelist) =>
whitelist.where((item) => item.isInGlobalWhitelist == isInGlobalWhitelist).map((item) => item.assetId).toSet();
bool areWhitelistsTheSame(List<ZanoAsset> whitelist1, List<ZanoAsset> whitelist2) {
return areSetsEqual(getSetFromWhitelist(whitelist1, true), getSetFromWhitelist(whitelist2, true)) &&
areSetsEqual(getSetFromWhitelist(whitelist1, false), getSetFromWhitelist(whitelist2, false));
}
void addOrUpdateBalance(ZanoAsset asset, Balance? _balance) {
if (balance.keys.any((element) => element is ZanoAsset && element.assetId == asset.assetId)) {
balance[balance.keys.firstWhere((element) => element is ZanoAsset && element.assetId == asset.assetId)] = _balance == null
? ZanoBalance.empty(decimalPoint: asset.decimalPoint)
: ZanoBalance(total: _balance.total, unlocked: _balance.unlocked, decimalPoint: asset.decimalPoint);
} else {
balance[asset] = _balance == null
? ZanoBalance.empty(decimalPoint: asset.decimalPoint)
: ZanoBalance(total: _balance.total, unlocked: _balance.unlocked, decimalPoint: asset.decimalPoint);
}
}
final whitelistsFromServer = await getAssetsWhitelist();
void loadWhitelists() {
debugPrint('loadWhitelists');
final globalWhitelist = whitelistsFromServer.where((item) => item.isInGlobalWhitelist);
final globalWhitelistIds = globalWhitelist.map((item) => item.assetId).toSet();
final localWhitelist = whitelistsFromServer.where((item) => !item.isInGlobalWhitelist && !globalWhitelistIds.contains(item.assetId));
for (final asset in globalWhitelist.followedBy(localWhitelist)) {
// we have two options:
// 1. adding as active (enabled) and adding to balance (even there's no balance for this asset)
// 2. checking if there's a balance, then setting enabled true or false
bool firstOption = 1 == 0;
if (firstOption) {
asset.enabled = true;
zanoAssetsBox.put(asset.assetId, ZanoAsset.copyWith(asset, _getIconPath(asset.title), enabled: true));
addOrUpdateBalance(asset, walletInfo.wi.balances.firstWhereOrNull((item) => item.assetId == asset.assetId));
} else {
final _balance = walletInfo.wi.balances.firstWhereOrNull((item) => item.assetId == asset.assetId);
zanoAssetsBox.put(asset.assetId, ZanoAsset.copyWith(asset, _getIconPath(asset.title), enabled: _balance != null));
addOrUpdateBalance(asset, _balance);
}
}
}
if (this.whitelists.isEmpty) {
if (zanoAssetsBox.isEmpty) loadWhitelists();
this.whitelists = whitelistsFromServer;
} else if (!areWhitelistsTheSame(whitelistsFromServer, this.whitelists)) {
// // updating whitelists from server
// if (zanoAssetsBox.isEmpty) {
// debugPrint('first loading of whitelists');
// loadWhitelists();
// } else {
// debugPrint('later updating of whitelists');
// }
debugPrint('whitelists changed!');
if (zanoAssetsBox.isEmpty) loadWhitelists();
this.whitelists = whitelistsFromServer;
}
// TODO: here should be synchronization of whitelists // TODO: here should be synchronization of whitelists
// for (final item in whitelists) { // for (final item in whitelists) {
// if (!zanoAssets.containsKey(item.assetId)) zanoAssets[item.assetId] = item; // if (!zanoAssets.containsKey(item.assetId)) zanoAssets[item.assetId] = item;
@ -400,23 +462,33 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
// // removing assets missing in whitelists (in case some were removed since last time) // // removing assets missing in whitelists (in case some were removed since last time)
// zanoAssets.removeWhere((key, _) => !whitelists.any((element) => element.assetId == key)); // zanoAssets.removeWhere((key, _) => !whitelists.any((element) => element.assetId == key));
for (final asset in balance.keys) {
if (asset == CryptoCurrency.zano) {
final _balance = walletInfo.wi.balances.firstWhere((element) => element.assetId == zanoAssetId);
balance[asset] = ZanoBalance(total: _balance.total, unlocked: _balance.unlocked);
} else if (asset is ZanoAsset) {
addOrUpdateBalance(asset, walletInfo.wi.balances.firstWhereOrNull((element) => element.assetId == asset.assetId));
}
}
/*
// matching balances and whitelists // matching balances and whitelists
// 1. show only balances available in whitelists // 1. show only balances available in whitelists
// 2. set whitelists available in balances as 'enabled' ('disabled' by default) // 2. set whitelists available in balances as 'enabled' ('disabled' by default)
for (final item in walletInfo.wi.balances) { for (final b in walletInfo.wi.balances) {
if (item.assetInfo.ticker == 'ZANO') { if (b.assetInfo.ticker == 'ZANO') {
balance[CryptoCurrency.zano] = ZanoBalance(total: item.total, unlocked: item.unlocked, decimalPoint: ZanoFormatter.defaultDecimalPoint); balance[CryptoCurrency.zano] = ZanoBalance(total: b.total, unlocked: b.unlocked, decimalPoint: ZanoFormatter.defaultDecimalPoint);
} else { } else {
final asset = zanoAssetsBox.get(item.assetInfo.assetId); final asset = zanoAssetsBox.get(b.assetInfo.assetId);
if (asset == null) { if (asset == null) {
debugPrint('balance for an unknown asset ${item.assetInfo.assetId}'); debugPrint('balance for an unknown asset ${b.assetInfo.assetId}');
continue; continue;
} }
if (balance.keys.any((element) => element is ZanoAsset && element.assetId == item.assetInfo.assetId)) { if (balance.keys.any((element) => element is ZanoAsset && element.assetId == b.assetInfo.assetId)) {
balance[balance.keys.firstWhere((element) => element is ZanoAsset && element.assetId == item.assetInfo.assetId)] = balance[balance.keys.firstWhere((element) => element is ZanoAsset && element.assetId == b.assetInfo.assetId)] =
ZanoBalance(total: item.total, unlocked: item.unlocked, decimalPoint: asset.decimalPoint); ZanoBalance(total: b.total, unlocked: b.unlocked, decimalPoint: asset.decimalPoint);
} else { } else {
balance[asset] = ZanoBalance(total: item.total, unlocked: item.unlocked, decimalPoint: asset.decimalPoint); balance[asset] = ZanoBalance(total: b.total, unlocked: b.unlocked, decimalPoint: asset.decimalPoint);
} }
//balance[asset] = ZanoBalance(total: item.total, unlocked: item.unlocked, decimalPoint: asset.decimalPoint); //balance[asset] = ZanoBalance(total: item.total, unlocked: item.unlocked, decimalPoint: asset.decimalPoint);
asset.enabled = true; asset.enabled = true;
@ -426,7 +498,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
balance.removeWhere( balance.removeWhere(
(key, _) => (key, _) =>
key != CryptoCurrency.zano && !walletInfo.wi.balances.any((element) => element.assetInfo.assetId == (key as ZanoAsset).assetId), key != CryptoCurrency.zano && !walletInfo.wi.balances.any((element) => element.assetInfo.assetId == (key as ZanoAsset).assetId),
); );*/
//if (_counter++ % 10 == 0) await _askForUpdateTransactionHistory(); //if (_counter++ % 10 == 0) await _askForUpdateTransactionHistory();
} }
@ -465,29 +537,29 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
if (assetDescriptor == null) { if (assetDescriptor == null) {
throw "there's no zano asset with id $assetId"; throw "there's no zano asset with id $assetId";
} }
String? iconPath; final iconPath = _getIconPath(assetDescriptor.title);
try { final asset = ZanoAsset.copyWith(assetDescriptor, iconPath, assetId: assetId, enabled: true);
iconPath = CryptoCurrency.all.firstWhere((element) => element.title.toUpperCase() == assetDescriptor.title.toUpperCase()).iconPath; zanoAssetsBox.put(asset.assetId, asset);
} catch (_) {} balance[asset] = ZanoBalance.empty(decimalPoint: asset.decimalPoint);
// TODO: copywith two times. was it intended
final asset = ZanoAsset.copyWith(assetDescriptor, iconPath, 'ZANO', assetId: assetId, enabled: true);
zanoAssetsBox.put(asset.assetId, ZanoAsset.copyWith(asset, iconPath, 'ZANO'));
balance[asset] = ZanoBalance(total: 0, unlocked: 0, decimalPoint: asset.decimalPoint);
return asset; return asset;
} }
Future<void> changeZanoAssetAvailability(ZanoAsset asset) async { String? _getIconPath(String title) {
String? iconPath;
try { try {
iconPath = CryptoCurrency.all.firstWhere((element) => element.title.toUpperCase() == asset.title.toUpperCase()).iconPath; return CryptoCurrency.all.firstWhere((element) => element.title.toUpperCase() == title.toUpperCase()).iconPath;
} catch (_) {} } catch (_) {}
zanoAssetsBox.put(asset.assetId, ZanoAsset.copyWith(asset, iconPath, 'ZANO')); return null;
}
Future<void> changeZanoAssetAvailability(ZanoAsset asset) async {
String? iconPath = _getIconPath(asset.title);
zanoAssetsBox.put(asset.assetId, ZanoAsset.copyWith(asset, iconPath));
if (asset.enabled) { if (asset.enabled) {
final assetDescriptor = await addAssetsWhitelist(asset.assetId); final assetDescriptor = await addAssetsWhitelist(asset.assetId);
if (assetDescriptor == null) { if (assetDescriptor == null) {
throw 'error adding zano asset'; throw 'error adding zano asset';
} }
balance[asset] = ZanoBalance(total: 0, unlocked: 0, decimalPoint: asset.decimalPoint); balance[asset] = ZanoBalance.empty(decimalPoint: asset.decimalPoint);
} else { } else {
final result = await removeAssetsWhitelist(asset.assetId); final result = await removeAssetsWhitelist(asset.assetId);
if (result == false) { if (result == false) {
@ -574,4 +646,8 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
// 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents; // 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents;
_onNewBlock.call(syncHeight, left, ptc); _onNewBlock.call(syncHeight, left, ptc);
} }
static void _info(String s) {
debugPrint('[info] $s');
}
} }

View file

@ -49,7 +49,7 @@ mixin ZanoWalletApi {
void closeWallet() => ApiCalls.closeWallet(hWallet: hWallet); void closeWallet() => ApiCalls.closeWallet(hWallet: hWallet);
Future<bool> setupNode() async { Future<bool> setupNode() async {
debugPrint('[info] init $_defaultNodeUri'); _info('init $_defaultNodeUri');
final result = ApiCalls.setupNode( final result = ApiCalls.setupNode(
address: _defaultNodeUri, address: _defaultNodeUri,
login: '', login: '',
@ -57,7 +57,7 @@ mixin ZanoWalletApi {
useSSL: false, useSSL: false,
isLightWallet: false, isLightWallet: false,
); );
debugPrint('[info] init result $result'); _info('init result $result');
return result; return result;
} }
@ -66,8 +66,7 @@ mixin ZanoWalletApi {
final result = GetWalletInfoResult.fromJson(jsonDecode(json) as Map<String, dynamic>); final result = GetWalletInfoResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
if (_logJson) debugPrint('get_wallet_info $json'); if (_logJson) debugPrint('get_wallet_info $json');
await _writeLog('get_wallet_info', 'get_wallet_info result $json'); await _writeLog('get_wallet_info', 'get_wallet_info result $json');
if (_logInfo) _info('get_wallet_info got ${result.wi.balances.length} balances: ${result.wi.balances} seed: ${_shorten(result.wiExtended.seed)}');
debugPrint('[info] get_wallet_info got ${result.wi.balances.length} balances: ${result.wi.balances} seed: ${_shorten(result.wiExtended.seed)}');
return result; return result;
} }
@ -81,8 +80,7 @@ mixin ZanoWalletApi {
if (_logJson) debugPrint('get_wallet_status $json'); if (_logJson) debugPrint('get_wallet_status $json');
await _writeLog('get_wallet_status', 'get_wallet_status result $json'); await _writeLog('get_wallet_status', 'get_wallet_status result $json');
if (_logInfo) if (_logInfo)
debugPrint( _info('get_wallet_status connected: ${status.isDaemonConnected} in refresh: ${status.isInLongRefresh} progress: ${status.progress} wallet state: ${status.walletState}');
'[info] get_wallet_status connected: ${status.isDaemonConnected} in refresh: ${status.isInLongRefresh} progress: ${status.progress} wallet state: ${status.walletState}');
return status; return status;
} }
@ -90,14 +88,25 @@ mixin ZanoWalletApi {
await _writeLog(methodName, 'invoke method $methodName params: ${jsonEncode(params)} hWallet: $hWallet'); await _writeLog(methodName, 'invoke method $methodName params: ${jsonEncode(params)} hWallet: $hWallet');
var invokeResult = var invokeResult =
ApiCalls.asyncCall(methodName: 'invoke', hWallet: hWallet, params: '{"method": "$methodName","params": ${jsonEncode(params)}}'); ApiCalls.asyncCall(methodName: 'invoke', hWallet: hWallet, params: '{"method": "$methodName","params": ${jsonEncode(params)}}');
var map = jsonDecode(invokeResult) as Map<String, dynamic>; Map<String, dynamic> map;
try {
map = jsonDecode(invokeResult) as Map<String, dynamic>;
} catch (e) {
debugPrint('exception in parsing json in invokeMethod: $invokeResult');
rethrow;
}
int attempts = 0; int attempts = 0;
if (map['job_id'] != null) { if (map['job_id'] != null) {
final jobId = map['job_id'] as int; final jobId = map['job_id'] as int;
do { do {
await Future.delayed(Duration(milliseconds: attempts < 2 ? 100 : 500)); await Future.delayed(Duration(milliseconds: attempts < 2 ? 100 : 500));
final result = ApiCalls.tryPullResult(jobId); final result = ApiCalls.tryPullResult(jobId);
try {
map = jsonDecode(result) as Map<String, dynamic>; map = jsonDecode(result) as Map<String, dynamic>;
} catch (e) {
debugPrint('exception in parsing json in invokeMethod: $result');
rethrow;
}
if (map['status'] != null && map['status'] == _statusDelivered && map['result'] != null) { if (map['status'] != null && map['status'] == _statusDelivered && map['result'] != null) {
await _writeLog(methodName, 'invoke method $methodName result $result'); await _writeLog(methodName, 'invoke method $methodName result $result');
return result; return result;
@ -114,13 +123,16 @@ mixin ZanoWalletApi {
if (_logJson) debugPrint('assets_whitelist_get $json'); if (_logJson) debugPrint('assets_whitelist_get $json');
final map = jsonDecode(json) as Map<String, dynamic>?; final map = jsonDecode(json) as Map<String, dynamic>?;
_checkForErrors(map); _checkForErrors(map);
List<ZanoAsset> assets(String type) => List<ZanoAsset> assets(String type, bool isGlobalWhitelist) =>
(map?['result']?['result']?[type] as List<dynamic>?)?.map((e) => ZanoAsset.fromJson(e as Map<String, dynamic>)).toList() ?? []; (map?['result']?['result']?[type] as List<dynamic>?)
final localWhitelist = assets('local_whitelist'); ?.map((e) => ZanoAsset.fromJson(e as Map<String, dynamic>, isInGlobalWhitelist: isGlobalWhitelist))
final globalWhitelist = assets('global_whitelist'); .toList() ??
final ownAssets = assets('own_assets'); [];
final localWhitelist = assets('local_whitelist', false);
final globalWhitelist = assets('global_whitelist', true);
final ownAssets = assets('own_assets', false);
if (_logInfo) if (_logInfo)
print('[info] assets_whitelist_get got local whitelist: ${localWhitelist.length} ($localWhitelist); ' _info('assets_whitelist_get got local whitelist: ${localWhitelist.length} ($localWhitelist); '
'global whitelist: ${globalWhitelist.length} ($globalWhitelist); ' 'global whitelist: ${globalWhitelist.length} ($globalWhitelist); '
'own assets: ${ownAssets.length} ($ownAssets)'); 'own assets: ${ownAssets.length} ($ownAssets)');
return [...localWhitelist, ...globalWhitelist, ...ownAssets]; return [...localWhitelist, ...globalWhitelist, ...ownAssets];
@ -138,10 +150,10 @@ mixin ZanoWalletApi {
_checkForErrors(map); _checkForErrors(map);
if (map!['result']!['result']!['status']! == 'OK') { if (map!['result']!['result']!['status']! == 'OK') {
final assetDescriptor = ZanoAsset.fromJson(map['result']!['result']!['asset_descriptor']! as Map<String, dynamic>); final assetDescriptor = ZanoAsset.fromJson(map['result']!['result']!['asset_descriptor']! as Map<String, dynamic>);
if (_logInfo) print('[info] assets_whitelist_add added ${assetDescriptor.fullName} ${assetDescriptor.ticker}'); _info('assets_whitelist_add added ${assetDescriptor.fullName} ${assetDescriptor.ticker}');
return assetDescriptor; return assetDescriptor;
} else { } else {
if (_logInfo) print('[info] assets_whitelist_add status ${map['result']!['result']!['status']!}'); _info('assets_whitelist_add status ${map['result']!['result']!['status']!}');
return null; return null;
} }
} catch (e) { } catch (e) {
@ -156,7 +168,7 @@ mixin ZanoWalletApi {
if (_logJson) print('assets_whitelist_remove $assetId $json'); if (_logJson) print('assets_whitelist_remove $assetId $json');
final map = jsonDecode(json) as Map<String, dynamic>?; final map = jsonDecode(json) as Map<String, dynamic>?;
_checkForErrors(map); _checkForErrors(map);
if (_logInfo) print('[info] assets_whitelist_remove status ${map!['result']!['result']!['status']!}'); _info('assets_whitelist_remove status ${map!['result']!['result']!['status']!}');
return (map!['result']!['result']!['status']! == 'OK'); return (map!['result']!['result']!['status']! == 'OK');
} catch (e) { } catch (e) {
print('[error] assets_whitelist_remove $e'); print('[error] assets_whitelist_remove $e');
@ -182,14 +194,14 @@ mixin ZanoWalletApi {
} }
final map = jsonDecode(result.body) as Map<String, dynamic>?; final map = jsonDecode(result.body) as Map<String, dynamic>?;
if (map!['error'] != null) { if (map!['error'] != null) {
if (_logInfo) print('[info] get_asset_info $assetId error ${map['error']!['code']} ${map['error']!['message']}'); _info('get_asset_info $assetId error ${map['error']!['code']} ${map['error']!['message']}');
return null; return null;
} else if (map['result']!['status']! == 'OK') { } else if (map['result']!['status']! == 'OK') {
final assetDescriptor = ZanoAsset.fromJson(map['result']!['asset_descriptor']! as Map<String, dynamic>); final assetDescriptor = ZanoAsset.fromJson(map['result']!['asset_descriptor']! as Map<String, dynamic>);
if (_logInfo) print('[info] get_asset_info $assetId ${assetDescriptor.fullName} ${assetDescriptor.ticker}'); _info('get_asset_info $assetId ${assetDescriptor.fullName} ${assetDescriptor.ticker}');
return assetDescriptor; return assetDescriptor;
} else { } else {
if (_logInfo) print('[info] get_asset_info $assetId status ${map['result']!['status']!}'); _info('get_asset_info $assetId status ${map['result']!['status']!}');
return null; return null;
} }
} }
@ -214,10 +226,10 @@ mixin ZanoWalletApi {
_checkForErrors(map); _checkForErrors(map);
final transfers = map?['result']?['result']?['transfers'] as List<dynamic>?; final transfers = map?['result']?['result']?['transfers'] as List<dynamic>?;
if (transfers == null) { if (transfers == null) {
if (_logInfo) print('[info] get_recent_txs_and_info empty transfers'); _info('get_recent_txs_and_info empty transfers');
return []; return [];
} }
if (_logInfo) print('[info] get_recent_txs_and_info transfers: ${transfers.length}'); _info('get_recent_txs_and_info transfers: ${transfers.length}');
return transfers.map((e) => Transfer.fromJson(e as Map<String, dynamic>)).toList(); return transfers.map((e) => Transfer.fromJson(e as Map<String, dynamic>)).toList();
} catch (e) { } catch (e) {
print('[error] get_recent_txs_and_info $e'); print('[error] get_recent_txs_and_info $e');
@ -232,7 +244,7 @@ mixin ZanoWalletApi {
String _shorten(String s) => s.length > 10 ? '${s.substring(0, 4)}...${s.substring(s.length - 4)}' : s; String _shorten(String s) => s.length > 10 ? '${s.substring(0, 4)}...${s.substring(s.length - 4)}' : s;
Future<CreateWalletResult> createWallet(String path, String password) async { Future<CreateWalletResult> createWallet(String path, String password) async {
if (_logInfo) debugPrint('[info] create_wallet path $path password ${_shorten(password)}'); _info('create_wallet path $path password ${_shorten(password)}');
await _writeLog('create_wallet', 'create_wallet path $path password ${_shorten(password)}'); await _writeLog('create_wallet', 'create_wallet path $path password ${_shorten(password)}');
final json = ApiCalls.createWallet(path: path, password: password); final json = ApiCalls.createWallet(path: path, password: password);
if (_logJson) debugPrint('create_wallet $json'); if (_logJson) debugPrint('create_wallet $json');
@ -247,12 +259,12 @@ mixin ZanoWalletApi {
throw ZanoWalletException('Error creating wallet file, empty response'); throw ZanoWalletException('Error creating wallet file, empty response');
} }
final result = CreateWalletResult.fromJson(map!['result'] as Map<String, dynamic>); final result = CreateWalletResult.fromJson(map!['result'] as Map<String, dynamic>);
if (_logInfo) debugPrint('[info] create_wallet ${result.name} ${result.seed}'); _info('create_wallet ${result.name} ${result.seed}');
return result; return result;
} }
Future<CreateWalletResult> restoreWalletFromSeed(String path, String password, String seed) async { Future<CreateWalletResult> restoreWalletFromSeed(String path, String password, String seed) async {
if (_logInfo) debugPrint('[info] restore_wallet path $path password ${_shorten(password)} seed ${_shorten(seed)}'); _info('restore_wallet path $path password ${_shorten(password)} seed ${_shorten(seed)}');
await _writeLog('restore_wallet', 'restore_wallet path $path password ${_shorten(password)} seed ${_shorten(seed)}'); await _writeLog('restore_wallet', 'restore_wallet path $path password ${_shorten(password)} seed ${_shorten(seed)}');
final json = ApiCalls.restoreWalletFromSeed(path: path, password: password, seed: seed); final json = ApiCalls.restoreWalletFromSeed(path: path, password: password, seed: seed);
if (_logJson) debugPrint('restore_wallet $json'); if (_logJson) debugPrint('restore_wallet $json');
@ -272,12 +284,12 @@ mixin ZanoWalletApi {
throw RestoreFromKeysException('Error restoring wallet, empty response'); throw RestoreFromKeysException('Error restoring wallet, empty response');
} }
final result = CreateWalletResult.fromJson(map!['result'] as Map<String, dynamic>); final result = CreateWalletResult.fromJson(map!['result'] as Map<String, dynamic>);
if (_logInfo) debugPrint('[info] restore_wallet ${result.name} ${result.wi.address}'); _info('restore_wallet ${result.name} ${result.wi.address}');
return result; return result;
} }
Future<CreateWalletResult> loadWallet(String path, String password, [bool secondAttempt = false]) async { Future<CreateWalletResult> loadWallet(String path, String password, [bool secondAttempt = false]) async {
if (_logInfo) debugPrint('[info] load_wallet path $path password ${_shorten(password)}'); _info('load_wallet path $path password ${_shorten(password)}');
await _writeLog('load_wallet', 'load_wallet path $path password ${_shorten(password)}'); await _writeLog('load_wallet', 'load_wallet path $path password ${_shorten(password)}');
final json = ApiCalls.loadWallet(path: path, password: password); final json = ApiCalls.loadWallet(path: path, password: password);
if (_logJson) debugPrint('load_wallet $json'); if (_logJson) debugPrint('load_wallet $json');
@ -300,7 +312,7 @@ mixin ZanoWalletApi {
throw ZanoWalletException('Error loading wallet, empty response'); throw ZanoWalletException('Error loading wallet, empty response');
} }
final result = CreateWalletResult.fromJson(map!['result'] as Map<String, dynamic>); final result = CreateWalletResult.fromJson(map!['result'] as Map<String, dynamic>);
if (_logInfo) debugPrint('[info] load_wallet ${result.name} ${result.wi.address}'); _info('load_wallet ${result.name} ${result.wi.address}');
return result; return result;
} }
@ -365,4 +377,10 @@ mixin ZanoWalletApi {
await logFile.writeAsString(' ' + matches.map((element) => '${element.group(0)}').join(', ') + '\n', mode: FileMode.append); await logFile.writeAsString(' ' + matches.map((element) => '${element.group(0)}').join(', ') + '\n', mode: FileMode.append);
} }
} }
static void _info(String s) {
if (_logInfo) {
debugPrint('[info] $s');
}
}
} }