mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-22 02:34:59 +00:00
whitelists
This commit is contained in:
parent
42731fcdcb
commit
89b572cae2
6 changed files with 174 additions and 73 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
@ -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';
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 => '';
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue