mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-03 09:29:48 +00:00
changed fields to BigInt, some fixes
This commit is contained in:
parent
e7b29c0a56
commit
02bfe643d9
26 changed files with 262 additions and 455 deletions
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
|
|
||||||
|
import 'package:cw_zano/api/utf8.dart';
|
||||||
import 'package:cw_zano/api/utf8_box.dart';
|
import 'package:cw_zano/api/utf8_box.dart';
|
||||||
import 'package:cw_zano/api/zano_api.dart';
|
import 'package:cw_zano/api/zano_api.dart';
|
||||||
import 'package:ffi/ffi.dart';
|
import 'package:ffi/ffi.dart';
|
||||||
|
@ -52,12 +53,13 @@ typedef _SetPassword = Pointer<Utf8> Function(int hWallet, Pointer<Utf8> passwor
|
||||||
|
|
||||||
// char* get_connectivity_status()
|
// char* get_connectivity_status()
|
||||||
// char* get_version()
|
// char* get_version()
|
||||||
|
// get_opened_wallets()
|
||||||
typedef _stringFunction = Pointer<Utf8> Function();
|
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.toDartString();
|
//final str = pointer.toDartString();
|
||||||
//final str = pointer.toDartStringAllowingMalformed();
|
final str = pointer.toDartStringAllowingMalformed();
|
||||||
calloc.free(pointer);
|
calloc.free(pointer);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@ -181,8 +183,11 @@ class ApiCalls {
|
||||||
static int getCurrentTxFee({required int priority}) => _getCurrentTxFeeNative(priority);
|
static int getCurrentTxFee({required int priority}) => _getCurrentTxFeeNative(priority);
|
||||||
|
|
||||||
static final _getConnectivityStatusNative = zanoApi.lookup<NativeFunction<_stringFunction>>('get_connectivity_status').asFunction<_stringFunction>();
|
static final _getConnectivityStatusNative = zanoApi.lookup<NativeFunction<_stringFunction>>('get_connectivity_status').asFunction<_stringFunction>();
|
||||||
|
|
||||||
static String getConnectivityStatus() => _performApiCall(() => _getConnectivityStatusNative());
|
static String getConnectivityStatus() => _performApiCall(() => _getConnectivityStatusNative());
|
||||||
|
|
||||||
|
static final _getOpenedWalletsNative = zanoApi.lookup<NativeFunction<_stringFunction>>('get_opened_wallets').asFunction<_stringFunction>();
|
||||||
|
static String getOpenedWallets() => _performApiCall(() => _getOpenedWalletsNative());
|
||||||
|
|
||||||
static final _getAddressInfoNative = zanoApi.lookup<NativeFunction<_GetAddressInfo>>('get_address_info').asFunction<_GetAddressInfo>();
|
static final _getAddressInfoNative = zanoApi.lookup<NativeFunction<_GetAddressInfo>>('get_address_info').asFunction<_GetAddressInfo>();
|
||||||
|
|
||||||
|
|
|
@ -2,4 +2,5 @@ class Consts {
|
||||||
static const errorWrongSeed = 'WRONG_SEED';
|
static const errorWrongSeed = 'WRONG_SEED';
|
||||||
static const errorAlreadyExists = 'ALREADY_EXISTS';
|
static const errorAlreadyExists = 'ALREADY_EXISTS';
|
||||||
static const errorWalletWrongId = 'WALLET_WRONG_ID';
|
static const errorWalletWrongId = 'WALLET_WRONG_ID';
|
||||||
|
static const errorBusy = 'BUSY';
|
||||||
}
|
}
|
|
@ -1,11 +1,12 @@
|
||||||
import 'package:cw_zano/model/zano_asset.dart';
|
import 'package:cw_zano/model/zano_asset.dart';
|
||||||
|
import 'package:cw_zano/zano_formatter.dart';
|
||||||
|
|
||||||
class Balance {
|
class Balance {
|
||||||
final ZanoAsset assetInfo;
|
final ZanoAsset assetInfo;
|
||||||
final int awaitingIn;
|
final BigInt awaitingIn;
|
||||||
final int awaitingOut;
|
final BigInt awaitingOut;
|
||||||
final int total;
|
final BigInt total;
|
||||||
final int unlocked;
|
final BigInt unlocked;
|
||||||
|
|
||||||
Balance(
|
Balance(
|
||||||
{required this.assetInfo,
|
{required this.assetInfo,
|
||||||
|
@ -22,9 +23,9 @@ class Balance {
|
||||||
factory Balance.fromJson(Map<String, dynamic> json) => Balance(
|
factory Balance.fromJson(Map<String, dynamic> json) => Balance(
|
||||||
assetInfo:
|
assetInfo:
|
||||||
ZanoAsset.fromJson(json['asset_info'] as Map<String, dynamic>? ?? {}),
|
ZanoAsset.fromJson(json['asset_info'] as Map<String, dynamic>? ?? {}),
|
||||||
awaitingIn: json['awaiting_in'] as int? ?? 0,
|
awaitingIn: ZanoFormatter.bigIntFromDynamic(json['awaiting_in']),
|
||||||
awaitingOut: json['awaiting_out'] as int? ?? 0,
|
awaitingOut: ZanoFormatter.bigIntFromDynamic(json['awaiting_out']),
|
||||||
total: json['total'] as int? ?? 0,
|
total: ZanoFormatter.bigIntFromDynamic(json['total']),
|
||||||
unlocked: json['unlocked'] as int? ?? 0,
|
unlocked: ZanoFormatter.bigIntFromDynamic(json['unlocked']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
|
import 'package:cw_zano/zano_formatter.dart';
|
||||||
|
|
||||||
class Receive {
|
class Receive {
|
||||||
final int amount;
|
final BigInt amount;
|
||||||
final String assetId;
|
final String assetId;
|
||||||
final int index;
|
final int index;
|
||||||
|
|
||||||
Receive({required this.amount, required this.assetId, required this.index});
|
Receive({required this.amount, required this.assetId, required this.index});
|
||||||
|
|
||||||
factory Receive.fromJson(Map<String, dynamic> json) => Receive(
|
factory Receive.fromJson(Map<String, dynamic> json) => Receive(
|
||||||
amount: json['amount'] as int? ?? 0,
|
amount: ZanoFormatter.bigIntFromDynamic(json['amount']),
|
||||||
assetId: json['asset_id'] as String? ?? '',
|
assetId: json['asset_id'] as String? ?? '',
|
||||||
index: json['index'] as int? ?? 0,
|
index: json['index'] as int? ?? 0,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
import 'package:cw_zano/zano_formatter.dart';
|
||||||
|
|
||||||
class Subtransfer {
|
class Subtransfer {
|
||||||
final int amount;
|
final BigInt amount;
|
||||||
final String assetId;
|
final String assetId;
|
||||||
final bool isIncome;
|
final bool isIncome;
|
||||||
|
|
||||||
|
@ -7,7 +9,7 @@ class Subtransfer {
|
||||||
{required this.amount, required this.assetId, required this.isIncome});
|
{required this.amount, required this.assetId, required this.isIncome});
|
||||||
|
|
||||||
factory Subtransfer.fromJson(Map<String, dynamic> json) => Subtransfer(
|
factory Subtransfer.fromJson(Map<String, dynamic> json) => Subtransfer(
|
||||||
amount: json['amount'] as int? ?? 0,
|
amount: ZanoFormatter.bigIntFromDynamic(json['amount']),
|
||||||
assetId: json['asset_id'] as String? ?? '',
|
assetId: json['asset_id'] as String? ?? '',
|
||||||
isIncome: json['is_income'] as bool? ?? false,
|
isIncome: json['is_income'] as bool? ?? false,
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,7 +3,9 @@ import 'package:cw_zano/api/model/subtransfer.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:cw_zano/model/zano_asset.dart';
|
import 'package:cw_zano/model/zano_asset.dart';
|
||||||
import 'package:cw_zano/model/zano_transaction_info.dart';
|
import 'package:cw_zano/model/zano_transaction_info.dart';
|
||||||
|
import 'package:cw_zano/zano_formatter.dart';
|
||||||
import 'package:cw_zano/zano_wallet.dart';
|
import 'package:cw_zano/zano_wallet.dart';
|
||||||
|
import 'package:cw_zano/zano_wallet_api.dart';
|
||||||
|
|
||||||
class Transfer {
|
class Transfer {
|
||||||
final String comment;
|
final String comment;
|
||||||
|
@ -71,8 +73,8 @@ class Transfer {
|
||||||
unlockTime: json['unlock_time'] as int? ?? 0,
|
unlockTime: json['unlock_time'] as int? ?? 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
static Map<String, ZanoTransactionInfo> makeMap(List<Transfer> transfers, Map<String, ZanoAsset> zanoAssets, int currentDaemonHeight) =>
|
static Map<String, ZanoTransactionInfo> makeMap(List<Transfer> transfers, Map<String, ZanoAsset> zanoAssets, int currentDaemonHeight) {
|
||||||
Map.fromIterable(
|
return Map.fromIterable(
|
||||||
transfers,
|
transfers,
|
||||||
key: (item) => (item as Transfer).txHash,
|
key: (item) => (item as Transfer).txHash,
|
||||||
value: (transfer) {
|
value: (transfer) {
|
||||||
|
@ -81,7 +83,7 @@ class Transfer {
|
||||||
Subtransfer? single = transfer.subtransfers.singleOrNull;
|
Subtransfer? single = transfer.subtransfers.singleOrNull;
|
||||||
if (transfer.subtransfers.length == 2) {
|
if (transfer.subtransfers.length == 2) {
|
||||||
final zano = transfer.subtransfers.firstWhereOrNull((element) => element.assetId == ZanoWalletBase.zanoAssetId);
|
final zano = transfer.subtransfers.firstWhereOrNull((element) => element.assetId == ZanoWalletBase.zanoAssetId);
|
||||||
if (zano != null && !zano.isIncome && zano.amount == transfer.fee) {
|
if (zano != null && !zano.isIncome && zano.amount == BigInt.from(transfer.fee)) {
|
||||||
single = transfer.subtransfers.firstWhere((element) => element.assetId != ZanoWalletBase.zanoAssetId);
|
single = transfer.subtransfers.firstWhere((element) => element.assetId != ZanoWalletBase.zanoAssetId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,18 +95,22 @@ class Transfer {
|
||||||
}
|
}
|
||||||
if (single.assetId != ZanoWalletBase.zanoAssetId) {
|
if (single.assetId != ZanoWalletBase.zanoAssetId) {
|
||||||
final asset = zanoAssets[single.assetId];
|
final asset = zanoAssets[single.assetId];
|
||||||
if (asset != null)
|
if (asset == null) {
|
||||||
return ZanoTransactionInfo.fromTransfer(
|
ZanoWalletApi.error('unknown asset ${single.assetId}');
|
||||||
transfer,
|
}
|
||||||
confirmations: currentDaemonHeight - transfer.height,
|
final ticker = asset == null ? '***' : asset.ticker;
|
||||||
isIncome: single.isIncome,
|
final decimalPoint = asset == null ? ZanoFormatter.defaultDecimalPoint : asset.decimalPoint;
|
||||||
assetId: single.assetId,
|
return ZanoTransactionInfo.fromTransfer(
|
||||||
amount: single.amount,
|
transfer,
|
||||||
tokenSymbol: isSimple ? asset.ticker : '*${asset.ticker}',
|
confirmations: currentDaemonHeight - transfer.height,
|
||||||
decimalPoint: asset.decimalPoint,
|
isIncome: single.isIncome,
|
||||||
);
|
assetId: single.assetId,
|
||||||
|
amount: single.amount,
|
||||||
|
tokenSymbol: isSimple ? ticker : '*${ticker}',
|
||||||
|
decimalPoint: decimalPoint,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
final amount = single.isIncome ? single.amount : single.amount - transfer.fee;
|
final amount = single.isIncome ? single.amount : single.amount - BigInt.from(transfer.fee);
|
||||||
return ZanoTransactionInfo.fromTransfer(
|
return ZanoTransactionInfo.fromTransfer(
|
||||||
transfer,
|
transfer,
|
||||||
confirmations: currentDaemonHeight - transfer.height,
|
confirmations: currentDaemonHeight - transfer.height,
|
||||||
|
@ -115,4 +121,5 @@ class Transfer {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,11 @@ class ZanoAsset extends CryptoCurrency with HiveObjectMixin {
|
||||||
@HiveField(7)
|
@HiveField(7)
|
||||||
final String metaInfo;
|
final String metaInfo;
|
||||||
@HiveField(8)
|
@HiveField(8)
|
||||||
final int currentSupply;
|
final BigInt currentSupply;
|
||||||
@HiveField(9)
|
@HiveField(9)
|
||||||
final bool hiddenSupply;
|
final bool hiddenSupply;
|
||||||
@HiveField(10)
|
@HiveField(10)
|
||||||
final int totalMaxSupply;
|
final BigInt totalMaxSupply;
|
||||||
@HiveField(11)
|
@HiveField(11)
|
||||||
final bool isInGlobalWhitelist;
|
final bool isInGlobalWhitelist;
|
||||||
|
|
||||||
|
@ -47,11 +47,11 @@ class ZanoAsset extends CryptoCurrency with HiveObjectMixin {
|
||||||
this.iconPath,
|
this.iconPath,
|
||||||
this.owner = defaultOwner,
|
this.owner = defaultOwner,
|
||||||
this.metaInfo = '',
|
this.metaInfo = '',
|
||||||
this.currentSupply = 0,
|
required this.currentSupply,
|
||||||
this.hiddenSupply = false,
|
this.hiddenSupply = false,
|
||||||
this.totalMaxSupply = 0,
|
required this.totalMaxSupply,
|
||||||
this.isInGlobalWhitelist = false,
|
this.isInGlobalWhitelist = false,
|
||||||
}) : _enabled = enabled,
|
}) : _enabled = enabled,
|
||||||
super(
|
super(
|
||||||
name: fullName,
|
name: fullName,
|
||||||
title: ticker.toUpperCase(),
|
title: ticker.toUpperCase(),
|
||||||
|
@ -86,17 +86,19 @@ class ZanoAsset extends CryptoCurrency with HiveObjectMixin {
|
||||||
|
|
||||||
factory ZanoAsset.fromJson(Map<String, dynamic> json, {bool isInGlobalWhitelist = false}) => 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: ZanoFormatter.bigIntFromDynamic(json['current_supply']),
|
||||||
decimalPoint: json['decimal_point'] as int? ?? ZanoFormatter.defaultDecimalPoint,
|
decimalPoint: json['decimal_point'] as int? ?? ZanoFormatter.defaultDecimalPoint,
|
||||||
fullName: json['full_name'] as String? ?? '',
|
fullName: json['full_name'] as String? ?? '',
|
||||||
hiddenSupply: json['hidden_supply'] as bool? ?? false,
|
hiddenSupply: json['hidden_supply'] as bool? ?? false,
|
||||||
metaInfo: json['meta_info'] as String? ?? '',
|
metaInfo: json['meta_info'] as String? ?? '',
|
||||||
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: ZanoFormatter.bigIntFromDynamic(json['total_max_supply']),
|
||||||
isInGlobalWhitelist: isInGlobalWhitelist,
|
isInGlobalWhitelist: isInGlobalWhitelist,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static const typeId = ZANO_ASSET_TYPE_ID;
|
static const typeId = ZANO_ASSET_TYPE_ID;
|
||||||
static const zanoAssetsBoxName = 'zanoAssetsBox';
|
static const zanoAssetsBoxName = 'zanoAssetsBox';
|
||||||
static const defaultOwner = '0000000000000000000000000000000000000000000000000000000000000000';
|
static const defaultOwner = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||||
|
|
|
@ -2,16 +2,16 @@ import 'package:cw_core/balance.dart';
|
||||||
import 'package:cw_zano/zano_formatter.dart';
|
import 'package:cw_zano/zano_formatter.dart';
|
||||||
|
|
||||||
class ZanoBalance extends Balance {
|
class ZanoBalance extends Balance {
|
||||||
final int total;
|
final BigInt total;
|
||||||
final int unlocked;
|
final BigInt unlocked;
|
||||||
final int decimalPoint;
|
final int decimalPoint;
|
||||||
ZanoBalance({required this.total, required this.unlocked, this.decimalPoint = ZanoFormatter.defaultDecimalPoint}) : super(unlocked, total - unlocked);
|
ZanoBalance({required this.total, required this.unlocked, this.decimalPoint = ZanoFormatter.defaultDecimalPoint}) : super(unlocked.isValidInt ? unlocked.toInt() : 0, (total - unlocked).isValidInt ? (total - unlocked).toInt() : 0);
|
||||||
|
|
||||||
ZanoBalance.empty({this.decimalPoint = ZanoFormatter.defaultDecimalPoint}): total = 0, unlocked = 0, super(0, 0);
|
ZanoBalance.empty({this.decimalPoint = ZanoFormatter.defaultDecimalPoint}): total = BigInt.zero, unlocked = BigInt.zero, super(0, 0);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAdditionalBalance => ZanoFormatter.intAmountToString(total - unlocked, decimalPoint);
|
String get formattedAdditionalBalance => ZanoFormatter.bigIntAmountToString(total - unlocked, decimalPoint);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAvailableBalance => ZanoFormatter.intAmountToString(unlocked, decimalPoint);
|
String get formattedAvailableBalance => ZanoFormatter.bigIntAmountToString(unlocked, decimalPoint);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,26 +11,27 @@ class ZanoTransactionInfo extends TransactionInfo {
|
||||||
required this.direction,
|
required this.direction,
|
||||||
required this.date,
|
required this.date,
|
||||||
required this.isPending,
|
required this.isPending,
|
||||||
required this.amount,
|
required this.zanoAmount,
|
||||||
required this.fee,
|
required this.fee,
|
||||||
required this.assetId,
|
required this.assetId,
|
||||||
required this.confirmations,
|
required this.confirmations,
|
||||||
required this.tokenSymbol,
|
required this.tokenSymbol,
|
||||||
required this.decimalPoint,
|
required this.decimalPoint,
|
||||||
});
|
}) : amount = zanoAmount.isValidInt ? zanoAmount.toInt() : 0;
|
||||||
|
|
||||||
ZanoTransactionInfo.fromTransfer(Transfer transfer,
|
ZanoTransactionInfo.fromTransfer(Transfer transfer,
|
||||||
{required int confirmations,
|
{required int confirmations,
|
||||||
required bool isIncome,
|
required bool isIncome,
|
||||||
required String assetId,
|
required String assetId,
|
||||||
required int amount,
|
required BigInt amount,
|
||||||
this.tokenSymbol = 'ZANO',
|
this.tokenSymbol = 'ZANO',
|
||||||
this.decimalPoint = ZanoFormatter.defaultDecimalPoint})
|
this.decimalPoint = ZanoFormatter.defaultDecimalPoint})
|
||||||
: id = transfer.txHash,
|
: id = transfer.txHash,
|
||||||
height = transfer.height,
|
height = transfer.height,
|
||||||
direction = isIncome ? TransactionDirection.incoming : TransactionDirection.outgoing,
|
direction = isIncome ? TransactionDirection.incoming : TransactionDirection.outgoing,
|
||||||
date = DateTime.fromMillisecondsSinceEpoch(transfer.timestamp * 1000),
|
date = DateTime.fromMillisecondsSinceEpoch(transfer.timestamp * 1000),
|
||||||
amount = amount,
|
zanoAmount = amount,
|
||||||
|
amount = amount.isValidInt ? amount.toInt() : 0,
|
||||||
fee = transfer.fee,
|
fee = transfer.fee,
|
||||||
assetId = assetId,
|
assetId = assetId,
|
||||||
confirmations = confirmations,
|
confirmations = confirmations,
|
||||||
|
@ -46,6 +47,7 @@ class ZanoTransactionInfo extends TransactionInfo {
|
||||||
final TransactionDirection direction;
|
final TransactionDirection direction;
|
||||||
final DateTime date;
|
final DateTime date;
|
||||||
final bool isPending;
|
final bool isPending;
|
||||||
|
final BigInt zanoAmount;
|
||||||
final int amount;
|
final int amount;
|
||||||
final int fee;
|
final int fee;
|
||||||
final int confirmations;
|
final int confirmations;
|
||||||
|
@ -57,7 +59,7 @@ class ZanoTransactionInfo extends TransactionInfo {
|
||||||
String? key;
|
String? key;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String amountFormatted() => '${formatAmount(ZanoFormatter.intAmountToString(amount, decimalPoint))} $tokenSymbol';
|
String amountFormatted() => '${formatAmount(ZanoFormatter.bigIntAmountToString(zanoAmount, decimalPoint))} $tokenSymbol';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String fiatAmount() => _fiatAmount ?? '';
|
String fiatAmount() => _fiatAmount ?? '';
|
||||||
|
|
|
@ -1,21 +1,26 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:cw_zano/zano_wallet_api.dart';
|
||||||
import 'package:decimal/decimal.dart';
|
import 'package:decimal/decimal.dart';
|
||||||
import 'package:decimal/intl.dart';
|
import 'package:decimal/intl.dart';
|
||||||
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
class ZanoFormatter {
|
class ZanoFormatter {
|
||||||
static const defaultDecimalPoint = 12;
|
static const defaultDecimalPoint = 12;
|
||||||
|
|
||||||
static final numberFormat = NumberFormat()
|
//static final numberFormat = NumberFormat()
|
||||||
..maximumFractionDigits = defaultDecimalPoint
|
// ..maximumFractionDigits = defaultDecimalPoint
|
||||||
..minimumFractionDigits = 1;
|
// ..minimumFractionDigits = 1;
|
||||||
|
|
||||||
static Decimal _bigIntDivision({required BigInt amount, required BigInt divider}) =>
|
static Decimal _bigIntDivision({required BigInt amount, required BigInt divider}) {
|
||||||
(Decimal.fromBigInt(amount) / Decimal.fromBigInt(divider)).toDecimal();
|
return (Decimal.fromBigInt(amount) / Decimal.fromBigInt(divider)).toDecimal();
|
||||||
|
}
|
||||||
|
|
||||||
static String intAmountToString(int amount, [int decimalPoint = defaultDecimalPoint]) => numberFormat
|
static String intAmountToString(int amount, [int decimalPoint = defaultDecimalPoint]) {
|
||||||
.format(
|
final numberFormat = NumberFormat()..maximumFractionDigits = decimalPoint
|
||||||
|
..minimumFractionDigits = 1;
|
||||||
|
return numberFormat.format(
|
||||||
DecimalIntl(
|
DecimalIntl(
|
||||||
_bigIntDivision(
|
_bigIntDivision(
|
||||||
amount: BigInt.from(amount),
|
amount: BigInt.from(amount),
|
||||||
|
@ -24,8 +29,12 @@ class ZanoFormatter {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.replaceAll(',', '');
|
.replaceAll(',', '');
|
||||||
static String bigIntAmountToString(BigInt amount, [int decimalPoint = defaultDecimalPoint]) => numberFormat
|
}
|
||||||
.format(
|
|
||||||
|
static String bigIntAmountToString(BigInt amount, [int decimalPoint = defaultDecimalPoint]) {
|
||||||
|
final numberFormat = NumberFormat()..maximumFractionDigits = decimalPoint
|
||||||
|
..minimumFractionDigits = 1;
|
||||||
|
return numberFormat.format(
|
||||||
DecimalIntl(
|
DecimalIntl(
|
||||||
_bigIntDivision(
|
_bigIntDivision(
|
||||||
amount: amount,
|
amount: amount,
|
||||||
|
@ -34,12 +43,32 @@ class ZanoFormatter {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.replaceAll(',', '');
|
.replaceAll(',', '');
|
||||||
|
}
|
||||||
|
|
||||||
static double intAmountToDouble(int amount, [int decimalPoint = defaultDecimalPoint]) => _bigIntDivision(
|
static double intAmountToDouble(int amount, [int decimalPoint = defaultDecimalPoint]) => _bigIntDivision(
|
||||||
amount: BigInt.from(amount),
|
amount: BigInt.from(amount),
|
||||||
divider: BigInt.from(pow(10, decimalPoint)),
|
divider: BigInt.from(pow(10, decimalPoint)),
|
||||||
).toDouble();
|
).toDouble();
|
||||||
|
|
||||||
static int parseAmount(String amount, [int decimalPoint = defaultDecimalPoint]) =>
|
static int parseAmount(String amount, [int decimalPoint = defaultDecimalPoint]) {
|
||||||
(Decimal.parse(amount) * Decimal.fromBigInt(BigInt.from(10).pow(decimalPoint))).toBigInt().toInt();
|
final resultBigInt = (Decimal.parse(amount) * Decimal.fromBigInt(BigInt.from(10).pow(decimalPoint))).toBigInt();
|
||||||
|
if (!resultBigInt.isValidInt) {
|
||||||
|
Fluttertoast.showToast(msg: 'Cannot transfer $amount. Maximum is ${intAmountToString(resultBigInt.toInt(), decimalPoint)}.');
|
||||||
|
}
|
||||||
|
return resultBigInt.toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
static BigInt bigIntFromDynamic(dynamic d) {
|
||||||
|
if (d is int) {
|
||||||
|
return BigInt.from(d);
|
||||||
|
} else if (d is BigInt) {
|
||||||
|
return d;
|
||||||
|
} else if (d == null) {
|
||||||
|
return BigInt.zero;
|
||||||
|
} else {
|
||||||
|
ZanoWalletApi.error('cannot cast value of type ${d.runtimeType} to BigInt');
|
||||||
|
throw 'cannot cast value of type ${d.runtimeType} to BigInt';
|
||||||
|
//return BigInt.zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import 'package:cw_core/wallet_info.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_recent_txs_and_info_result.dart';
|
import 'package:cw_zano/api/model/get_recent_txs_and_info_result.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/get_wallet_status_result.dart';
|
||||||
import 'package:cw_zano/api/model/transfer.dart';
|
import 'package:cw_zano/api/model/transfer.dart';
|
||||||
import 'package:cw_zano/model/pending_zano_transaction.dart';
|
import 'package:cw_zano/model/pending_zano_transaction.dart';
|
||||||
|
@ -29,6 +30,8 @@ import 'package:cw_zano/zano_wallet_addresses.dart';
|
||||||
import 'package:cw_zano/zano_wallet_api.dart';
|
import 'package:cw_zano/zano_wallet_api.dart';
|
||||||
import 'package:cw_zano/zano_wallet_exceptions.dart';
|
import 'package:cw_zano/zano_wallet_exceptions.dart';
|
||||||
import 'package:cw_zano/zano_wallet_service.dart';
|
import 'package:cw_zano/zano_wallet_service.dart';
|
||||||
|
import 'package:cw_zano/api/model/balance.dart';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
@ -39,6 +42,7 @@ class ZanoWallet = ZanoWalletBase with _$ZanoWallet;
|
||||||
abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHistory, ZanoTransactionInfo> with Store, ZanoWalletApi {
|
abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHistory, ZanoTransactionInfo> with Store, ZanoWalletApi {
|
||||||
static const int _autoSaveIntervalSeconds = 30;
|
static const int _autoSaveIntervalSeconds = 30;
|
||||||
static const int _pollIntervalMilliseconds = 2000;
|
static const int _pollIntervalMilliseconds = 2000;
|
||||||
|
static const int _maxLoadAssetsRetries = 5;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ZanoWalletAddresses walletAddresses;
|
ZanoWalletAddresses walletAddresses;
|
||||||
|
@ -101,7 +105,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
await wallet.connectToNode(node: Node());
|
await wallet.connectToNode(node: Node());
|
||||||
final path = await pathForWallet(name: credentials.name, type: credentials.walletInfo!.type);
|
final path = await pathForWallet(name: credentials.name, type: credentials.walletInfo!.type);
|
||||||
final createWalletResult = await wallet.createWallet(path, credentials.password!);
|
final createWalletResult = await wallet.createWallet(path, credentials.password!);
|
||||||
await _parseCreateWalletResult(createWalletResult, wallet);
|
await wallet.parseCreateWalletResult(createWalletResult);
|
||||||
await wallet.init(createWalletResult.wi.address);
|
await wallet.init(createWalletResult.wi.address);
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
@ -111,7 +115,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
await wallet.connectToNode(node: Node());
|
await wallet.connectToNode(node: Node());
|
||||||
final path = await pathForWallet(name: credentials.name, type: credentials.walletInfo!.type);
|
final path = await pathForWallet(name: credentials.name, type: credentials.walletInfo!.type);
|
||||||
final createWalletResult = await wallet.restoreWalletFromSeed(path, credentials.password!, credentials.mnemonic);
|
final createWalletResult = await wallet.restoreWalletFromSeed(path, credentials.password!, credentials.mnemonic);
|
||||||
await _parseCreateWalletResult(createWalletResult, wallet);
|
await wallet.parseCreateWalletResult(createWalletResult);
|
||||||
await wallet.init(createWalletResult.wi.address);
|
await wallet.init(createWalletResult.wi.address);
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
@ -121,19 +125,20 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
final wallet = ZanoWallet(walletInfo);
|
final wallet = ZanoWallet(walletInfo);
|
||||||
await wallet.connectToNode(node: Node());
|
await wallet.connectToNode(node: Node());
|
||||||
final createWalletResult = await wallet.loadWallet(path, password);
|
final createWalletResult = await wallet.loadWallet(path, password);
|
||||||
await _parseCreateWalletResult(createWalletResult, wallet);
|
await wallet.parseCreateWalletResult(createWalletResult);
|
||||||
await wallet.init(createWalletResult.wi.address);
|
await wallet.init(createWalletResult.wi.address);
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> _parseCreateWalletResult(CreateWalletResult result, ZanoWallet wallet) async {
|
Future<void> parseCreateWalletResult(CreateWalletResult result) async {
|
||||||
wallet.hWallet = result.walletId;
|
hWallet = result.walletId;
|
||||||
wallet.seed = result.seed;
|
seed = result.seed;
|
||||||
ZanoWalletApi.info('setting hWallet = ${result.walletId}');
|
ZanoWalletApi.info('setting hWallet = ${result.walletId}');
|
||||||
wallet.walletAddresses.address = result.wi.address;
|
walletAddresses.address = result.wi.address;
|
||||||
|
await loadAssets(result.wi.balances, maxRetries: _maxLoadAssetsRetries);
|
||||||
for (final item in result.wi.balances) {
|
for (final item in result.wi.balances) {
|
||||||
if (item.assetInfo.assetId == zanoAssetId) {
|
if (item.assetInfo.assetId == zanoAssetId) {
|
||||||
wallet.balance[CryptoCurrency.zano] = ZanoBalance(
|
balance[CryptoCurrency.zano] = ZanoBalance(
|
||||||
total: item.total,
|
total: item.total,
|
||||||
unlocked: item.unlocked,
|
unlocked: item.unlocked,
|
||||||
);
|
);
|
||||||
|
@ -141,9 +146,9 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
}
|
}
|
||||||
if (result.recentHistory.history != null) {
|
if (result.recentHistory.history != null) {
|
||||||
final transfers = result.recentHistory.history!;
|
final transfers = result.recentHistory.history!;
|
||||||
final transactions = Transfer.makeMap(transfers, wallet.zanoAssets, wallet.currentDaemonHeight);
|
final transactions = Transfer.makeMap(transfers, zanoAssets, currentDaemonHeight);
|
||||||
wallet.transactionHistory.addMany(transactions);
|
transactionHistory.addMany(transactions);
|
||||||
await wallet.transactionHistory.save();
|
await transactionHistory.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,8 +172,8 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
final isZano = credentials.currency == CryptoCurrency.zano;
|
final isZano = credentials.currency == CryptoCurrency.zano;
|
||||||
final outputs = credentials.outputs;
|
final outputs = credentials.outputs;
|
||||||
final hasMultiDestination = outputs.length > 1;
|
final hasMultiDestination = outputs.length > 1;
|
||||||
final unlockedBalanceZano = BigInt.from(balance[CryptoCurrency.zano]?.unlocked ?? 0);
|
final unlockedBalanceZano = balance[CryptoCurrency.zano]?.unlocked ?? BigInt.zero;
|
||||||
final unlockedBalanceCurrency = BigInt.from(balance[credentials.currency]?.unlocked ?? 0);
|
final unlockedBalanceCurrency = balance[credentials.currency]?.unlocked ?? BigInt.zero;
|
||||||
final fee = BigInt.from(calculateEstimatedFee(credentials.priority));
|
final fee = BigInt.from(calculateEstimatedFee(credentials.priority));
|
||||||
late BigInt totalAmount;
|
late BigInt totalAmount;
|
||||||
void checkForEnoughBalances() {
|
void checkForEnoughBalances() {
|
||||||
|
@ -184,7 +189,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
}
|
}
|
||||||
if (totalAmount > unlockedBalanceCurrency) {
|
if (totalAmount > unlockedBalanceCurrency) {
|
||||||
throw ZanoTransactionCreationException(
|
throw ZanoTransactionCreationException(
|
||||||
"You don't have enough coins (required: ${ZanoFormatter.bigIntAmountToString(totalAmount)} ${credentials.currency.title}, unlocked ${ZanoFormatter.bigIntAmountToString(unlockedBalanceZano)} ${credentials.currency.title}).");
|
"You don't have enough coins (required: ${ZanoFormatter.bigIntAmountToString(totalAmount, credentials.currency.decimals)} ${credentials.currency.title}, unlocked ${ZanoFormatter.bigIntAmountToString(unlockedBalanceCurrency, credentials.currency.decimals)} ${credentials.currency.title}).");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,18 +246,14 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
try {
|
try {
|
||||||
final transfers = <Transfer>[];
|
final transfers = <Transfer>[];
|
||||||
late GetRecentTxsAndInfoResult result;
|
late GetRecentTxsAndInfoResult result;
|
||||||
bool first = true;
|
|
||||||
do {
|
do {
|
||||||
result = await getRecentTxsAndInfo(offset: _lastTxIndex, count: _txChunkSize);
|
result = await getRecentTxsAndInfo(offset: _lastTxIndex, count: _txChunkSize);
|
||||||
// TODO: that's for debug purposes
|
|
||||||
if (first && result.transfers.isEmpty) break;
|
|
||||||
first = false;
|
|
||||||
_lastTxIndex += result.transfers.length;
|
_lastTxIndex += result.transfers.length;
|
||||||
transfers.addAll(result.transfers);
|
transfers.addAll(result.transfers);
|
||||||
} while (result.lastItemIndex + 1 < result.totalTransfers);
|
} while (result.lastItemIndex + 1 < result.totalTransfers);
|
||||||
return Transfer.makeMap(transfers, zanoAssets, currentDaemonHeight);
|
return Transfer.makeMap(transfers, zanoAssets, currentDaemonHeight);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
ZanoWalletApi.error(e.toString());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,7 +298,33 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
await store();
|
await store();
|
||||||
await walletAddresses.updateAddressesInBox();
|
await walletAddresses.updateAddressesInBox();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error while saving Zano wallet file ${e.toString()}');
|
ZanoWalletApi.error('Error while saving Zano wallet file ${e.toString()}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> loadAssets(List<Balance> balances, {int maxRetries = 1}) async {
|
||||||
|
List<ZanoAsset> assets = [];
|
||||||
|
int retryCount = 0;
|
||||||
|
|
||||||
|
while (retryCount < maxRetries) {
|
||||||
|
try {
|
||||||
|
assets = await getAssetsWhitelist();
|
||||||
|
break;
|
||||||
|
} on ZanoWalletBusyException {
|
||||||
|
if (retryCount < maxRetries - 1) {
|
||||||
|
retryCount++;
|
||||||
|
await Future.delayed(Duration(seconds: 1));
|
||||||
|
} else {
|
||||||
|
ZanoWalletApi.error('failed to load assets after $retryCount retries');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zanoAssets = {};
|
||||||
|
for (final asset in assets) {
|
||||||
|
final newAsset = ZanoAsset.copyWith(asset,
|
||||||
|
icon: _getIconPath(asset.title), enabled: balances.any((element) => element.assetId == asset.assetId));
|
||||||
|
zanoAssets.putIfAbsent(asset.assetId, () => newAsset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +335,13 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
_lastKnownBlockHeight = 0;
|
_lastKnownBlockHeight = 0;
|
||||||
_initialSyncHeight = 0;
|
_initialSyncHeight = 0;
|
||||||
_updateSyncInfoTimer ??= Timer.periodic(Duration(milliseconds: _pollIntervalMilliseconds), (_) async {
|
_updateSyncInfoTimer ??= Timer.periodic(Duration(milliseconds: _pollIntervalMilliseconds), (_) async {
|
||||||
final walletStatus = await getWalletStatus();
|
GetWalletStatusResult walletStatus;
|
||||||
|
// ignoring get wallet status exception (in case of wrong wallet id)
|
||||||
|
try {
|
||||||
|
walletStatus = await getWalletStatus();
|
||||||
|
} on ZanoWalletException {
|
||||||
|
return;
|
||||||
|
}
|
||||||
currentDaemonHeight = walletStatus.currentDaemonHeight;
|
currentDaemonHeight = walletStatus.currentDaemonHeight;
|
||||||
_updateSyncProgress(walletStatus);
|
_updateSyncProgress(walletStatus);
|
||||||
|
|
||||||
|
@ -322,14 +355,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
publicSpendKey: walletInfo.wiExtended.spendPublicKey,
|
publicSpendKey: walletInfo.wiExtended.spendPublicKey,
|
||||||
publicViewKey: walletInfo.wiExtended.viewPublicKey,
|
publicViewKey: walletInfo.wiExtended.viewPublicKey,
|
||||||
);
|
);
|
||||||
|
loadAssets(walletInfo.wi.balances);
|
||||||
final assets = await getAssetsWhitelist();
|
|
||||||
zanoAssets = {};
|
|
||||||
for (final asset in assets) {
|
|
||||||
final newAsset = ZanoAsset.copyWith(asset,
|
|
||||||
icon: _getIconPath(asset.title), enabled: walletInfo.wi.balances.any((element) => element.assetId == asset.assetId));
|
|
||||||
zanoAssets.putIfAbsent(asset.assetId, () => newAsset);
|
|
||||||
}
|
|
||||||
// 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)
|
||||||
|
@ -358,8 +384,8 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
syncStatus = FailedSyncStatus();
|
syncStatus = FailedSyncStatus();
|
||||||
print(e);
|
ZanoWalletApi.error(e.toString());
|
||||||
rethrow;
|
//rethrow; // TODO: we don't need to propagate exception here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,7 +403,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
await transactionHistory.save();
|
await transactionHistory.save();
|
||||||
_isTransactionUpdating = false;
|
_isTransactionUpdating = false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
ZanoWalletApi.error(e.toString());
|
||||||
_isTransactionUpdating = false;
|
_isTransactionUpdating = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -407,12 +433,12 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
if (asset.enabled) {
|
if (asset.enabled) {
|
||||||
final assetDescriptor = await addAssetsWhitelist(asset.assetId);
|
final assetDescriptor = await addAssetsWhitelist(asset.assetId);
|
||||||
if (assetDescriptor == null) {
|
if (assetDescriptor == null) {
|
||||||
print('Error adding zano asset');
|
ZanoWalletApi.error('Error adding zano asset');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final result = await removeAssetsWhitelist(asset.assetId);
|
final result = await removeAssetsWhitelist(asset.assetId);
|
||||||
if (result == false) {
|
if (result == false) {
|
||||||
print('Error removing zano asset');
|
ZanoWalletApi.error('Error removing zano asset');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -441,7 +467,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
|
||||||
syncStatus = SyncingSyncStatus(blocksLeft, ptc);
|
syncStatus = SyncingSyncStatus(blocksLeft, ptc);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e.toString());
|
ZanoWalletApi.error(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:cw_core/wallet_addresses.dart';
|
import 'package:cw_core/wallet_addresses.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_zano/zano_wallet_api.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
part 'zano_wallet_addresses.g.dart';
|
part 'zano_wallet_addresses.g.dart';
|
||||||
|
@ -33,7 +34,7 @@ abstract class ZanoWalletAddressesBase extends WalletAddresses with Store {
|
||||||
addressesMap[address] = '';
|
addressesMap[address] = '';
|
||||||
await saveAddressesInBox();
|
await saveAddressesInBox();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e.toString());
|
ZanoWalletApi.error(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert' as convert;
|
||||||
|
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
import 'package:cw_zano/api/api_calls.dart';
|
import 'package:cw_zano/api/api_calls.dart';
|
||||||
|
@ -20,14 +20,16 @@ import 'package:cw_zano/api/model/transfer_result.dart';
|
||||||
import 'package:cw_zano/model/zano_asset.dart';
|
import 'package:cw_zano/model/zano_asset.dart';
|
||||||
import 'package:cw_zano/zano_wallet_exceptions.dart';
|
import 'package:cw_zano/zano_wallet_exceptions.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:json_bigint/json_bigint.dart';
|
||||||
|
|
||||||
mixin ZanoWalletApi {
|
mixin ZanoWalletApi {
|
||||||
static const _defaultNodeUri = '195.201.107.230:33336';
|
static const _defaultNodeUri = '195.201.107.230:33336';
|
||||||
static const _statusDelivered = 'delivered';
|
static const _statusDelivered = 'delivered';
|
||||||
static const _maxInvokeAttempts = 10;
|
static const _maxInvokeAttempts = 10;
|
||||||
|
static const _maxReopenAttempts = 5;
|
||||||
static const _logInfo = true;
|
static const _logInfo = true;
|
||||||
static const _logError = true;
|
static const _logError = true;
|
||||||
static const _logJson = true;
|
static const _logJson = false;
|
||||||
static const int _zanoMixinValue = 10;
|
static const int _zanoMixinValue = 10;
|
||||||
|
|
||||||
int _hWallet = 0;
|
int _hWallet = 0;
|
||||||
|
@ -40,6 +42,9 @@ mixin ZanoWalletApi {
|
||||||
|
|
||||||
int getCurrentTxFee(TransactionPriority priority) => ApiCalls.getCurrentTxFee(priority: priority.raw);
|
int getCurrentTxFee(TransactionPriority priority) => ApiCalls.getCurrentTxFee(priority: priority.raw);
|
||||||
|
|
||||||
|
String getOpenedWallets() => ApiCalls.getOpenedWallets();
|
||||||
|
String getConnectivityStatus() => ApiCalls.getConnectivityStatus();
|
||||||
|
|
||||||
void setPassword(String password) => ApiCalls.setPassword(hWallet: hWallet, password: password);
|
void setPassword(String password) => ApiCalls.setPassword(hWallet: hWallet, password: password);
|
||||||
|
|
||||||
void closeWallet([int? walletToClose]) {
|
void closeWallet([int? walletToClose]) {
|
||||||
|
@ -65,7 +70,6 @@ mixin ZanoWalletApi {
|
||||||
final json = ApiCalls.getWalletInfo(hWallet);
|
final json = ApiCalls.getWalletInfo(hWallet);
|
||||||
final result = GetWalletInfoResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
|
final result = GetWalletInfoResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
|
||||||
_json('get_wallet_info', json);
|
_json('get_wallet_info', json);
|
||||||
//await _writeLog('get_wallet_info', 'get_wallet_info result $json');
|
|
||||||
info('get_wallet_info got ${result.wi.balances.length} balances: ${result.wi.balances} seed: ${_shorten(result.wiExtended.seed)}');
|
info('get_wallet_info got ${result.wi.balances.length} balances: ${result.wi.balances} seed: ${_shorten(result.wiExtended.seed)}');
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +82,6 @@ mixin ZanoWalletApi {
|
||||||
}
|
}
|
||||||
final status = GetWalletStatusResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
|
final status = GetWalletStatusResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
|
||||||
_json('get_wallet_status', json);
|
_json('get_wallet_status', json);
|
||||||
//await _writeLog('get_wallet_status', 'get_wallet_status result $json');
|
|
||||||
if (_logInfo)
|
if (_logInfo)
|
||||||
info(
|
info(
|
||||||
'get_wallet_status connected: ${status.isDaemonConnected} in refresh: ${status.isInLongRefresh} progress: ${status.progress} wallet state: ${status.walletState}');
|
'get_wallet_status connected: ${status.isDaemonConnected} in refresh: ${status.isInLongRefresh} progress: ${status.progress} wallet state: ${status.walletState}');
|
||||||
|
@ -86,13 +89,13 @@ mixin ZanoWalletApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> invokeMethod(String methodName, Object params) async {
|
Future<String> invokeMethod(String methodName, Object params) async {
|
||||||
//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)}}');
|
||||||
Map<String, dynamic> map;
|
Map<String, dynamic> map;
|
||||||
try {
|
try {
|
||||||
map = jsonDecode(invokeResult) as Map<String, dynamic>;
|
map = jsonDecode(invokeResult) as Map<String, dynamic>;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (invokeResult.contains(Consts.errorWalletWrongId)) throw ZanoWalletException('Wrong wallet id');
|
||||||
error('exception in parsing json in invokeMethod: $invokeResult');
|
error('exception in parsing json in invokeMethod: $invokeResult');
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
|
@ -105,16 +108,15 @@ mixin ZanoWalletApi {
|
||||||
try {
|
try {
|
||||||
map = jsonDecode(result) as Map<String, dynamic>;
|
map = jsonDecode(result) as Map<String, dynamic>;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (result.contains(Consts.errorWalletWrongId)) throw ZanoWalletException('Wrong wallet id');
|
||||||
error('exception in parsing json in invokeMethod: $result');
|
error('exception in parsing json in invokeMethod: $result');
|
||||||
rethrow;
|
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');
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} while (++attempts < _maxInvokeAttempts);
|
} while (++attempts < _maxInvokeAttempts);
|
||||||
}
|
}
|
||||||
//await _writeLog(methodName, 'invoke method $methodName result: $invokeResult');
|
|
||||||
return invokeResult;
|
return invokeResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +141,8 @@ mixin ZanoWalletApi {
|
||||||
return [...globalWhitelist, ...localWhitelist, ...ownAssets];
|
return [...globalWhitelist, ...localWhitelist, ...ownAssets];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error('assets_whitelist_get $e');
|
error('assets_whitelist_get $e');
|
||||||
return [];
|
//return [];
|
||||||
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +193,7 @@ mixin ZanoWalletApi {
|
||||||
final result = await _proxyToDaemon('/json_rpc', '{"method": "$methodName","params": ${jsonEncode(params)}}');
|
final result = await _proxyToDaemon('/json_rpc', '{"method": "$methodName","params": ${jsonEncode(params)}}');
|
||||||
_json('$methodName $assetId', result?.body ?? '');
|
_json('$methodName $assetId', result?.body ?? '');
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
debugPrint('get_asset_info empty result');
|
error('get_asset_info empty result');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final map = jsonDecode(result.body) as Map<String, dynamic>?;
|
final map = jsonDecode(result.body) as Map<String, dynamic>?;
|
||||||
|
@ -253,10 +256,8 @@ mixin ZanoWalletApi {
|
||||||
|
|
||||||
Future<CreateWalletResult> createWallet(String path, String password) async {
|
Future<CreateWalletResult> createWallet(String path, String password) async {
|
||||||
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)}');
|
|
||||||
final json = ApiCalls.createWallet(path: path, password: password);
|
final json = ApiCalls.createWallet(path: path, password: password);
|
||||||
_json('create_wallet', json);
|
_json('create_wallet', json);
|
||||||
//await _writeLog('create_wallet', 'create_wallet result $json');
|
|
||||||
final map = jsonDecode(json) as Map<String, dynamic>?;
|
final map = jsonDecode(json) as Map<String, dynamic>?;
|
||||||
if (map?['error'] != null) {
|
if (map?['error'] != null) {
|
||||||
final code = map!['error']!['code'] ?? '';
|
final code = map!['error']!['code'] ?? '';
|
||||||
|
@ -273,10 +274,8 @@ mixin ZanoWalletApi {
|
||||||
|
|
||||||
Future<CreateWalletResult> restoreWalletFromSeed(String path, String password, String seed) async {
|
Future<CreateWalletResult> restoreWalletFromSeed(String path, String password, String seed) async {
|
||||||
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)}');
|
|
||||||
final json = ApiCalls.restoreWalletFromSeed(path: path, password: password, seed: seed);
|
final json = ApiCalls.restoreWalletFromSeed(path: path, password: password, seed: seed);
|
||||||
_json('restore_wallet', json);
|
_json('restore_wallet', json);
|
||||||
//await _writeLog('restore_wallet', 'restore_wallet result $json');
|
|
||||||
final map = jsonDecode(json) as Map<String, dynamic>?;
|
final map = jsonDecode(json) as Map<String, dynamic>?;
|
||||||
if (map?['error'] != null) {
|
if (map?['error'] != null) {
|
||||||
final code = map!['error']!['code'] ?? '';
|
final code = map!['error']!['code'] ?? '';
|
||||||
|
@ -298,15 +297,19 @@ mixin ZanoWalletApi {
|
||||||
|
|
||||||
Future<CreateWalletResult> loadWallet(String path, String password, [int attempt = 0]) async {
|
Future<CreateWalletResult> loadWallet(String path, String password, [int attempt = 0]) async {
|
||||||
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)}');
|
final String json;
|
||||||
final json = ApiCalls.loadWallet(path: path, password: password);
|
try {
|
||||||
|
json = ApiCalls.loadWallet(path: path, password: password);
|
||||||
|
} catch (e) {
|
||||||
|
error('error in loadingWallet $e');
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
_json('load_wallet', json);
|
_json('load_wallet', json);
|
||||||
//await _writeLog('load_wallet', 'load_wallet result $json');
|
|
||||||
final map = jsonDecode(json) as Map<String, dynamic>?;
|
final map = jsonDecode(json) as Map<String, dynamic>?;
|
||||||
if (map?['error'] != null) {
|
if (map?['error'] != null) {
|
||||||
final code = map?['error']!['code'] ?? '';
|
final code = map?['error']!['code'] ?? '';
|
||||||
final message = map?['error']!['message'] ?? '';
|
final message = map?['error']!['message'] ?? '';
|
||||||
if (code == Consts.errorAlreadyExists && attempt <= 5) {
|
if (code == Consts.errorAlreadyExists && attempt <= _maxReopenAttempts) {
|
||||||
// already connected to this wallet. closing and trying to reopen
|
// already connected to this wallet. closing and trying to reopen
|
||||||
info('already connected. closing and reopen wallet (attempt $attempt)');
|
info('already connected. closing and reopen wallet (attempt $attempt)');
|
||||||
closeWallet(attempt);
|
closeWallet(attempt);
|
||||||
|
@ -347,11 +350,11 @@ mixin ZanoWalletApi {
|
||||||
final errorCode = resultMap['error']['code'];
|
final errorCode = resultMap['error']['code'];
|
||||||
final code = errorCode is int ? errorCode.toString() : errorCode as String? ?? '';
|
final code = errorCode is int ? errorCode.toString() : errorCode as String? ?? '';
|
||||||
final message = resultMap['error']['message'] as String? ?? '';
|
final message = resultMap['error']['message'] as String? ?? '';
|
||||||
debugPrint('transfer error $code $message');
|
error('transfer error $code $message');
|
||||||
throw TransferException('Transfer error, $message ($code)');
|
throw TransferException('Transfer error, $message ($code)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debugPrint('transfer error empty result');
|
error('transfer error empty result');
|
||||||
throw TransferException('Transfer error, empty result');
|
throw TransferException('Transfer error, empty result');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,6 +369,9 @@ mixin ZanoWalletApi {
|
||||||
if (result['error'] != null) {
|
if (result['error'] != null) {
|
||||||
final code = result['error']!['code'] ?? '';
|
final code = result['error']!['code'] ?? '';
|
||||||
final message = result['error']!['message'] ?? '';
|
final message = result['error']!['message'] ?? '';
|
||||||
|
if (code == -1 && message == Consts.errorBusy) {
|
||||||
|
throw ZanoWalletBusyException();
|
||||||
|
}
|
||||||
throw ZanoWalletException('Error, $message ($code)');
|
throw ZanoWalletException('Error, $message ($code)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -382,5 +388,18 @@ mixin ZanoWalletApi {
|
||||||
|
|
||||||
static void info(String s) => _logInfo ? debugPrint('[info] $s') : null;
|
static void info(String s) => _logInfo ? debugPrint('[info] $s') : null;
|
||||||
static void error(String s) => _logError ? debugPrint('[error] $s') : null;
|
static void error(String s) => _logError ? debugPrint('[error] $s') : null;
|
||||||
static void _json(String methodName, String json) => _logJson ? debugPrint('$methodName $json') : null;
|
static void printWrapped(String text) => RegExp('.{1,800}').allMatches(text).map((m) => m.group(0)).forEach(print);
|
||||||
|
static void _json(String methodName, String json) => _logJson ? printWrapped('$methodName $json') : null;
|
||||||
|
|
||||||
|
Map<String, dynamic> jsonDecode(String json) {
|
||||||
|
try {
|
||||||
|
return decodeJson(json.replaceAll("\\/", "/")) as Map<String, dynamic>;
|
||||||
|
} catch (e) {
|
||||||
|
return convert.jsonDecode(json) as Map<String, dynamic>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String jsonEncode(Object? object) {
|
||||||
|
return convert.jsonEncode(object);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,4 +12,8 @@ class RestoreFromKeysException extends ZanoWalletException {
|
||||||
|
|
||||||
class TransferException extends ZanoWalletException {
|
class TransferException extends ZanoWalletException {
|
||||||
TransferException(String message): super(message);
|
TransferException(String message): super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ZanoWalletBusyException extends ZanoWalletException {
|
||||||
|
ZanoWalletBusyException(): super('');
|
||||||
}
|
}
|
|
@ -9,6 +9,7 @@ import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cw_zano/api/api_calls.dart';
|
import 'package:cw_zano/api/api_calls.dart';
|
||||||
import 'package:cw_zano/zano_wallet.dart';
|
import 'package:cw_zano/zano_wallet.dart';
|
||||||
|
import 'package:cw_zano/zano_wallet_api.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
class ZanoNewWalletCredentials extends WalletCredentials {
|
class ZanoNewWalletCredentials extends WalletCredentials {
|
||||||
|
@ -54,7 +55,7 @@ class ZanoWalletService extends WalletService<ZanoNewWalletCredentials,
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ZanoWallet> create(WalletCredentials credentials, {bool? isTestnet}) async {
|
Future<ZanoWallet> create(WalletCredentials credentials, {bool? isTestnet}) async {
|
||||||
print('zanowallet service create isTestnet $isTestnet');
|
ZanoWalletApi.info('zanowallet service create isTestnet $isTestnet');
|
||||||
return await ZanoWalletBase.create(credentials: credentials);
|
return await ZanoWalletBase.create(credentials: credentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -250,6 +250,19 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_web_plugins:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
fluttertoast:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: fluttertoast
|
||||||
|
sha256: "4215b0085ebf737120ab6b06fefeadfae709c74f880a351a73d6d007f74e7631"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.1.4"
|
||||||
frontend_server_client:
|
frontend_server_client:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -346,6 +359,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.8.0"
|
version: "4.8.0"
|
||||||
|
json_bigint:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: json_bigint
|
||||||
|
sha256: "77f5cc47ec936b37ff5016394b0ed136fe2231e35dcbaed32fe749c221264cac"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -490,6 +511,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.5"
|
version: "2.1.5"
|
||||||
|
petitparser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: petitparser
|
||||||
|
sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.4.0"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -737,4 +766,4 @@ packages:
|
||||||
version: "3.1.1"
|
version: "3.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.2.0-0 <4.0.0"
|
dart: ">=3.2.0-0 <4.0.0"
|
||||||
flutter: ">=3.0.0"
|
flutter: ">=3.7.0"
|
||||||
|
|
|
@ -21,6 +21,8 @@ dependencies:
|
||||||
decimal: ^2.3.3
|
decimal: ^2.3.3
|
||||||
cw_core:
|
cw_core:
|
||||||
path: ../cw_core
|
path: ../cw_core
|
||||||
|
json_bigint: ^3.0.0
|
||||||
|
fluttertoast: 8.1.4
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
@ -76,6 +76,8 @@ class DecimalAmountValidator extends TextValidator {
|
||||||
return '^([0-9]+([.\,][0-9]{1,12})?|[.\,][0-9]{1,12})\$';
|
return '^([0-9]+([.\,][0-9]{1,12})?|[.\,][0-9]{1,12})\$';
|
||||||
case CryptoCurrency.btc:
|
case CryptoCurrency.btc:
|
||||||
return '^([0-9]+([.\,][0-9]{1,8})?|[.\,][0-9]{1,8})\$';
|
return '^([0-9]+([.\,][0-9]{1,8})?|[.\,][0-9]{1,8})\$';
|
||||||
|
case CryptoCurrency.zano:
|
||||||
|
return '^([0-9]+([.\,][0-9]{1,12})?|[.\,][0-9]{1,18})\$';
|
||||||
default:
|
default:
|
||||||
return '^([0-9]+([.\,][0-9]{1,12})?|[.\,][0-9]{1,12})\$';
|
return '^([0-9]+([.\,][0-9]{1,12})?|[.\,][0-9]{1,12})\$';
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,331 +0,0 @@
|
||||||
part of 'haven.dart';
|
|
||||||
|
|
||||||
class CWHavenAccountList extends HavenAccountList {
|
|
||||||
CWHavenAccountList(this._wallet);
|
|
||||||
|
|
||||||
final Object _wallet;
|
|
||||||
|
|
||||||
@override
|
|
||||||
@computed
|
|
||||||
ObservableList<Account> get accounts {
|
|
||||||
final havenWallet = _wallet as HavenWallet;
|
|
||||||
final accounts = havenWallet.walletAddresses.accountList.accounts
|
|
||||||
.map((acc) => Account(id: acc.id, label: acc.label))
|
|
||||||
.toList();
|
|
||||||
return ObservableList<Account>.of(accounts);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void update(Object wallet) {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
havenWallet.walletAddresses.accountList.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void refresh(Object wallet) {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
havenWallet.walletAddresses.accountList.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Account> getAll(Object wallet) {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
return havenWallet.walletAddresses.accountList
|
|
||||||
.getAll()
|
|
||||||
.map((acc) => Account(id: acc.id, label: acc.label))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> addAccount(Object wallet, {required String label}) async {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
await havenWallet.walletAddresses.accountList.addAccount(label: label);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> setLabelAccount(Object wallet,
|
|
||||||
{required int accountIndex, required String label}) async {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
await havenWallet.walletAddresses.accountList
|
|
||||||
.setLabelAccount(accountIndex: accountIndex, label: label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CWHavenSubaddressList extends MoneroSubaddressList {
|
|
||||||
CWHavenSubaddressList(this._wallet);
|
|
||||||
|
|
||||||
final Object _wallet;
|
|
||||||
|
|
||||||
@override
|
|
||||||
@computed
|
|
||||||
ObservableList<Subaddress> get subaddresses {
|
|
||||||
final havenWallet = _wallet as HavenWallet;
|
|
||||||
final subAddresses = havenWallet.walletAddresses.subaddressList.subaddresses
|
|
||||||
.map((sub) => Subaddress(id: sub.id, address: sub.address, label: sub.label))
|
|
||||||
.toList();
|
|
||||||
return ObservableList<Subaddress>.of(subAddresses);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void update(Object wallet, {required int accountIndex}) {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
havenWallet.walletAddresses.subaddressList.update(accountIndex: accountIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void refresh(Object wallet, {required int accountIndex}) {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
havenWallet.walletAddresses.subaddressList.refresh(accountIndex: accountIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Subaddress> getAll(Object wallet) {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
return havenWallet.walletAddresses.subaddressList
|
|
||||||
.getAll()
|
|
||||||
.map((sub) => Subaddress(id: sub.id, label: sub.label, address: sub.address))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> addSubaddress(Object wallet,
|
|
||||||
{required int accountIndex, required String label}) async {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
await havenWallet.walletAddresses.subaddressList
|
|
||||||
.addSubaddress(accountIndex: accountIndex, label: label);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> setLabelSubaddress(Object wallet,
|
|
||||||
{required int accountIndex, required int addressIndex, required String label}) async {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
await havenWallet.walletAddresses.subaddressList
|
|
||||||
.setLabelSubaddress(accountIndex: accountIndex, addressIndex: addressIndex, label: label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CWHavenWalletDetails extends HavenWalletDetails {
|
|
||||||
CWHavenWalletDetails(this._wallet);
|
|
||||||
|
|
||||||
final Object _wallet;
|
|
||||||
|
|
||||||
@computed
|
|
||||||
@override
|
|
||||||
Account get account {
|
|
||||||
final havenWallet = _wallet as HavenWallet;
|
|
||||||
final acc = havenWallet.walletAddresses.account as monero_account.Account;
|
|
||||||
return Account(id: acc.id, label: acc.label);
|
|
||||||
}
|
|
||||||
|
|
||||||
@computed
|
|
||||||
@override
|
|
||||||
HavenBalance get balance {
|
|
||||||
final havenWallet = _wallet as HavenWallet;
|
|
||||||
final balance = havenWallet.balance;
|
|
||||||
throw Exception('Unimplemented');
|
|
||||||
//return HavenBalance(
|
|
||||||
// fullBalance: balance.fullBalance,
|
|
||||||
// unlockedBalance: balance.unlockedBalance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CWHaven extends Haven {
|
|
||||||
@override
|
|
||||||
HavenAccountList getAccountList(Object wallet) {
|
|
||||||
return CWHavenAccountList(wallet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
MoneroSubaddressList getSubaddressList(Object wallet) {
|
|
||||||
return CWHavenSubaddressList(wallet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
TransactionHistoryBase getTransactionHistory(Object wallet) {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
return havenWallet.transactionHistory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
HavenWalletDetails getMoneroWalletDetails(Object wallet) {
|
|
||||||
return CWHavenWalletDetails(wallet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int getHeightByDate({required DateTime date}) => getHavenHeightByDate(date: date);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<int> getCurrentHeight() => getHavenCurrentHeight();
|
|
||||||
|
|
||||||
@override
|
|
||||||
TransactionPriority getDefaultTransactionPriority() {
|
|
||||||
return MoneroTransactionPriority.automatic;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
TransactionPriority deserializeMoneroTransactionPriority({required int raw}) {
|
|
||||||
return MoneroTransactionPriority.deserialize(raw: raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<TransactionPriority> getTransactionPriorities() {
|
|
||||||
return MoneroTransactionPriority.all;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<String> getMoneroWordList(String language) {
|
|
||||||
switch (language.toLowerCase()) {
|
|
||||||
case 'english':
|
|
||||||
return EnglishMnemonics.words;
|
|
||||||
case 'chinese (simplified)':
|
|
||||||
return ChineseSimplifiedMnemonics.words;
|
|
||||||
case 'dutch':
|
|
||||||
return DutchMnemonics.words;
|
|
||||||
case 'german':
|
|
||||||
return GermanMnemonics.words;
|
|
||||||
case 'japanese':
|
|
||||||
return JapaneseMnemonics.words;
|
|
||||||
case 'portuguese':
|
|
||||||
return PortugueseMnemonics.words;
|
|
||||||
case 'russian':
|
|
||||||
return RussianMnemonics.words;
|
|
||||||
case 'spanish':
|
|
||||||
return SpanishMnemonics.words;
|
|
||||||
case 'french':
|
|
||||||
return FrenchMnemonics.words;
|
|
||||||
case 'italian':
|
|
||||||
return ItalianMnemonics.words;
|
|
||||||
default:
|
|
||||||
return EnglishMnemonics.words;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
WalletCredentials createHavenRestoreWalletFromKeysCredentials(
|
|
||||||
{required String name,
|
|
||||||
required String spendKey,
|
|
||||||
required String viewKey,
|
|
||||||
required String address,
|
|
||||||
required String password,
|
|
||||||
required String language,
|
|
||||||
required int height}) {
|
|
||||||
return HavenRestoreWalletFromKeysCredentials(
|
|
||||||
name: name,
|
|
||||||
spendKey: spendKey,
|
|
||||||
viewKey: viewKey,
|
|
||||||
address: address,
|
|
||||||
password: password,
|
|
||||||
language: language,
|
|
||||||
height: height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
WalletCredentials createHavenRestoreWalletFromSeedCredentials(
|
|
||||||
{required String name,
|
|
||||||
required String password,
|
|
||||||
required int height,
|
|
||||||
required String mnemonic}) {
|
|
||||||
return HavenRestoreWalletFromSeedCredentials(
|
|
||||||
name: name, password: password, height: height, mnemonic: mnemonic);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
WalletCredentials createHavenNewWalletCredentials(
|
|
||||||
{required String name, required String language, String? password}) {
|
|
||||||
return HavenNewWalletCredentials(name: name, password: password, language: language);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, String> getKeys(Object wallet) {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
final keys = havenWallet.keys;
|
|
||||||
return <String, String>{
|
|
||||||
'privateSpendKey': keys.privateSpendKey,
|
|
||||||
'privateViewKey': keys.privateViewKey,
|
|
||||||
'publicSpendKey': keys.publicSpendKey,
|
|
||||||
'publicViewKey': keys.publicViewKey
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Object createHavenTransactionCreationCredentials(
|
|
||||||
{required List<Output> outputs,
|
|
||||||
required TransactionPriority priority,
|
|
||||||
required String assetType}) {
|
|
||||||
return HavenTransactionCreationCredentials(
|
|
||||||
outputs: outputs
|
|
||||||
.map((out) => OutputInfo(
|
|
||||||
fiatAmount: out.fiatAmount,
|
|
||||||
cryptoAmount: out.cryptoAmount,
|
|
||||||
address: out.address,
|
|
||||||
note: out.note,
|
|
||||||
sendAll: out.sendAll,
|
|
||||||
extractedAddress: out.extractedAddress,
|
|
||||||
isParsedAddress: out.isParsedAddress,
|
|
||||||
formattedCryptoAmount: out.formattedCryptoAmount))
|
|
||||||
.toList(),
|
|
||||||
priority: priority as MoneroTransactionPriority,
|
|
||||||
assetType: assetType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String formatterMoneroAmountToString({required int amount}) {
|
|
||||||
return moneroAmountToString(amount: amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
double formatterMoneroAmountToDouble({required int amount}) {
|
|
||||||
return moneroAmountToDouble(amount: amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int formatterMoneroParseAmount({required String amount}) {
|
|
||||||
return moneroParseAmount(amount: amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Account getCurrentAccount(Object wallet) {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
final acc = havenWallet.walletAddresses.account as monero_account.Account;
|
|
||||||
return Account(id: acc.id, label: acc.label);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void setCurrentAccount(Object wallet, int id, String label) {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
havenWallet.walletAddresses.account = monero_account.Account(id: id, label: label);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onStartup() {
|
|
||||||
monero_wallet_api.onStartup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int getTransactionInfoAccountId(TransactionInfo tx) {
|
|
||||||
final havenTransactionInfo = tx as HavenTransactionInfo;
|
|
||||||
return havenTransactionInfo.accountIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
WalletService createHavenWalletService(Box<WalletInfo> walletInfoSource) {
|
|
||||||
return HavenWalletService(walletInfoSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex) {
|
|
||||||
final havenWallet = wallet as HavenWallet;
|
|
||||||
return havenWallet.getTransactionAddress(accountIndex, addressIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
CryptoCurrency assetOfTransaction(TransactionInfo tx) {
|
|
||||||
final transaction = tx as HavenTransactionInfo;
|
|
||||||
final asset = CryptoCurrency.fromString(transaction.assetType);
|
|
||||||
return asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<AssetRate> getAssetRate() =>
|
|
||||||
getRate().map((rate) => AssetRate(rate.getAssetType(), rate.getRate())).toList();
|
|
||||||
}
|
|
|
@ -88,9 +88,7 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_balanceViewModel.wallet.type == WalletType.zano) {
|
if (_balanceViewModel.wallet.type == WalletType.zano) {
|
||||||
// TODO: assuming that token is Erc20Token
|
await zano!.addZanoAssetById(_balanceViewModel.wallet, contractAddress);
|
||||||
token as Erc20Token;
|
|
||||||
await zano!.addZanoAssetById(_balanceViewModel.wallet, token.contractAddress);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateTokensList();
|
_updateTokensList();
|
||||||
|
|
|
@ -177,7 +177,7 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||||
final asset = zano!.assetOfTransaction(balanceViewModel.wallet, transaction);
|
final asset = zano!.assetOfTransaction(balanceViewModel.wallet, transaction);
|
||||||
final price = balanceViewModel.fiatConvertationStore.prices[asset];
|
final price = balanceViewModel.fiatConvertationStore.prices[asset];
|
||||||
amount = calculateFiatAmountRaw(
|
amount = calculateFiatAmountRaw(
|
||||||
cryptoAmount: zano!.formatterIntAmountToDouble(amount: transaction.amount, currency: asset),
|
cryptoAmount: zano!.formatterIntAmountToDouble(amount: transaction.amount, currency: asset, forFee: false),
|
||||||
price: price);
|
price: price);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -183,7 +183,7 @@ abstract class OutputBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_wallet.type == WalletType.zano) {
|
if (_wallet.type == WalletType.zano) {
|
||||||
return zano!.formatterIntAmountToDouble(amount: fee, currency: cryptoCurrencyHandler());
|
return zano!.formatterIntAmountToDouble(amount: fee, currency: cryptoCurrencyHandler(), forFee: true);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e.toString());
|
print(e.toString());
|
||||||
|
|
|
@ -20,6 +20,7 @@ import 'package:cake_wallet/view_model/send/send_view_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:cw_core/transaction_direction.dart';
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
|
import 'package:cw_zano/model/zano_transaction_info.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:intl/src/intl/date_format.dart';
|
import 'package:intl/src/intl/date_format.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
@ -497,9 +498,11 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _addZanoListItems(TransactionInfo tx, DateFormat dateFormat) {
|
void _addZanoListItems(TransactionInfo tx, DateFormat dateFormat) {
|
||||||
|
tx as ZanoTransactionInfo;
|
||||||
final comment = tx.additionalInfo['comment'] as String?;
|
final comment = tx.additionalInfo['comment'] as String?;
|
||||||
items.addAll([
|
items.addAll([
|
||||||
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
|
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||||
|
StandartListItem(title: 'Asset ID', value: tx.assetId),
|
||||||
StandartListItem(
|
StandartListItem(
|
||||||
title: S.current.transaction_details_date, value: dateFormat.format(tx.date)),
|
title: S.current.transaction_details_date, value: dateFormat.format(tx.date)),
|
||||||
StandartListItem(title: S.current.transaction_details_height, value: '${tx.height}'),
|
StandartListItem(title: S.current.transaction_details_height, value: '${tx.height}'),
|
||||||
|
|
|
@ -102,7 +102,9 @@ class CWZano extends Zano {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double formatterIntAmountToDouble({required int amount, required CryptoCurrency currency}) {
|
double formatterIntAmountToDouble({required int amount, required CryptoCurrency currency, required bool forFee}) {
|
||||||
|
// fee always counted in zano with default decimal points
|
||||||
|
if (forFee) return ZanoFormatter.intAmountToDouble(amount);
|
||||||
if (currency is ZanoAsset) return ZanoFormatter.intAmountToDouble(amount, currency.decimalPoint);
|
if (currency is ZanoAsset) return ZanoFormatter.intAmountToDouble(amount, currency.decimalPoint);
|
||||||
return ZanoFormatter.intAmountToDouble(amount);
|
return ZanoFormatter.intAmountToDouble(amount);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ abstract class Zano {
|
||||||
WalletCredentials createZanoRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic});
|
WalletCredentials createZanoRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic});
|
||||||
WalletCredentials createZanoNewWalletCredentials({required String name, String password});
|
WalletCredentials createZanoNewWalletCredentials({required String name, String password});
|
||||||
Object createZanoTransactionCredentials({required List<Output> outputs, required TransactionPriority priority, required CryptoCurrency currency});
|
Object createZanoTransactionCredentials({required List<Output> outputs, required TransactionPriority priority, required CryptoCurrency currency});
|
||||||
double formatterIntAmountToDouble({required int amount, required CryptoCurrency currency});
|
double formatterIntAmountToDouble({required int amount, required CryptoCurrency currency, required bool forFee});
|
||||||
int formatterParseAmount({required String amount, required CryptoCurrency currency});
|
int formatterParseAmount({required String amount, required CryptoCurrency currency});
|
||||||
WalletService createZanoWalletService(Box<WalletInfo> walletInfoSource);
|
WalletService createZanoWalletService(Box<WalletInfo> walletInfoSource);
|
||||||
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo tx);
|
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo tx);
|
||||||
|
|
|
@ -1394,7 +1394,7 @@ abstract class Zano {
|
||||||
WalletCredentials createZanoRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic});
|
WalletCredentials createZanoRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic});
|
||||||
WalletCredentials createZanoNewWalletCredentials({required String name, String password});
|
WalletCredentials createZanoNewWalletCredentials({required String name, String password});
|
||||||
Object createZanoTransactionCredentials({required List<Output> outputs, required TransactionPriority priority, required CryptoCurrency currency});
|
Object createZanoTransactionCredentials({required List<Output> outputs, required TransactionPriority priority, required CryptoCurrency currency});
|
||||||
double formatterIntAmountToDouble({required int amount, required CryptoCurrency currency});
|
double formatterIntAmountToDouble({required int amount, required CryptoCurrency currency, required bool forFee});
|
||||||
int formatterParseAmount({required String amount, required CryptoCurrency currency});
|
int formatterParseAmount({required String amount, required CryptoCurrency currency});
|
||||||
WalletService createZanoWalletService(Box<WalletInfo> walletInfoSource);
|
WalletService createZanoWalletService(Box<WalletInfo> walletInfoSource);
|
||||||
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo tx);
|
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo tx);
|
||||||
|
|
Loading…
Reference in a new issue