added multiple destinations, send all flag; some refactoring

This commit is contained in:
leo1234 2024-03-08 18:50:34 +08:00
parent ba2dde7564
commit 43e9cd284a
15 changed files with 216 additions and 369 deletions

View file

@ -1,5 +1,5 @@
class Destination {
final String amount;
final int amount; // transfered as string
final String address;
final String assetId;
@ -7,13 +7,13 @@ class Destination {
{required this.amount, required this.address, required this.assetId});
factory Destination.fromJson(Map<String, dynamic> json) => Destination(
amount: json['amount'] as String,
amount: int.parse(json['amount'] as String),
address: json['address'] as String,
assetId: json['asset_id'] as String,
);
Map<String, dynamic> toJson() => {
"amount": amount,
"amount": amount.toString(),
"address": address,
"asset_id": assetId,
};

View file

@ -8,6 +8,7 @@ class GetWalletInfoResult {
GetWalletInfoResult({required this.wi, required this.wiExtended});
factory GetWalletInfoResult.fromJson(Map<String, dynamic> json) => GetWalletInfoResult(
wi: Wi.fromJson(json['wi'] as Map<String, dynamic>),
wiExtended: WiExtended.fromJson(json['wi_extended'] as Map<String, dynamic>));
}
wi: Wi.fromJson(json['wi'] as Map<String, dynamic>? ?? {}),
wiExtended: WiExtended.fromJson(json['wi_extended'] as Map<String, dynamic>? ?? {}),
);
}

View file

@ -16,11 +16,11 @@ class GetWalletStatusResult {
factory GetWalletStatusResult.fromJson(Map<String, dynamic> json) =>
GetWalletStatusResult(
currentDaemonHeight: json['current_daemon_height'] as int,
currentWalletHeight: json['current_wallet_height'] as int,
isDaemonConnected: json['is_daemon_connected'] as bool,
isInLongRefresh: json['is_in_long_refresh'] as bool,
progress: json['progress'] as int,
walletState: json['wallet_state'] as int,
currentDaemonHeight: json['current_daemon_height'] as int? ?? 0,
currentWalletHeight: json['current_wallet_height'] as int? ?? 0,
isDaemonConnected: json['is_daemon_connected'] as bool? ?? false,
isInLongRefresh: json['is_in_long_refresh'] as bool? ?? false,
progress: json['progress'] as int? ?? 0,
walletState: json['wallet_state'] as int? ?? 0,
);
}

View file

@ -30,12 +30,12 @@ class TransferParams {
};
factory TransferParams.fromJson(Map<String, dynamic> json) => TransferParams(
destinations: (json['destinations'] as List<dynamic>).map((e) => Destination.fromJson(e as Map<String, dynamic>)).toList(),
fee: json['fee'] as int,
mixin: json['mixin'] as int,
paymentId: json['payment_id'] as String,
comment: json['comment'] as String,
pushPayer: json["push_payer"] as bool,
hideReceiver: json["hide_receiver"] as bool,
destinations: (json['destinations'] as List<dynamic>?)?.map((e) => Destination.fromJson(e as Map<String, dynamic>)).toList() ?? [],
fee: json['fee'] as int? ?? 0,
mixin: json['mixin'] as int? ?? 0,
paymentId: json['payment_id'] as String? ?? '',
comment: json['comment'] as String? ?? '',
pushPayer: json["push_payer"] as bool? ?? false,
hideReceiver: json["hide_receiver"] as bool? ?? false,
);
}

View file

@ -6,8 +6,8 @@ class TransferResult {
TransferResult({required this.txHash, required this.txSize, required this.txUnsignedHex});
factory TransferResult.fromJson(Map<String, dynamic> json) => TransferResult(
txHash: json['tx_hash'] as String,
txSize: json['tx_size'] as int,
txUnsignedHex: json['tx_unsigned_hex'] as String,
txHash: json['tx_hash'] as String? ?? '',
txSize: json['tx_size'] as int? ?? 0,
txUnsignedHex: json['tx_unsigned_hex'] as String? ?? '',
);
}

View file

@ -19,14 +19,14 @@ class Wi {
required this.viewSecKey});
factory Wi.fromJson(Map<String, dynamic> json) => Wi(
address: json['address'] as String,
balances: (json['balances'] as List<dynamic>)
address: json['address'] as String? ?? '',
balances: (json['balances'] as List<dynamic>? ?? [])
.map((e) => Balance.fromJson(e as Map<String, dynamic>))
.toList(),
isAuditable: json['is_auditable'] as bool,
isWatchOnly: json['is_watch_only'] as bool,
minedTotal: json['mined_total'] as int,
path: json['path'] as String,
viewSecKey: json['view_sec_key'] as String,
isAuditable: json['is_auditable'] as bool? ?? false,
isWatchOnly: json['is_watch_only'] as bool? ?? false,
minedTotal: json['mined_total'] as int? ?? 0,
path: json['path'] as String? ?? '',
viewSecKey: json['view_sec_key'] as String? ?? '',
);
}

View file

@ -8,10 +8,10 @@ class WiExtended {
WiExtended({required this.seed, required this.spendPrivateKey, required this.spendPublicKey, required this.viewPrivateKey, required this.viewPublicKey});
factory WiExtended.fromJson(Map<String, dynamic> json) => WiExtended(
seed: json["seed"] as String,
spendPrivateKey: json["spend_private_key"] as String,
spendPublicKey: json["spend_public_key"] as String,
viewPrivateKey: json["view_private_key"] as String,
viewPublicKey: json["view_public_key"] as String,
seed: json["seed"] as String? ?? '',
spendPrivateKey: json["spend_private_key"] as String? ?? '',
spendPublicKey: json["spend_public_key"] as String? ?? '',
viewPrivateKey: json["view_private_key"] as String? ?? '',
viewPublicKey: json["view_public_key"] as String? ?? '',
);
}

View file

@ -1,113 +0,0 @@
import 'dart:async';
import 'dart:convert';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_zano/api/api_calls.dart' as calls;
import 'package:cw_zano/api/api_calls.dart';
import 'package:cw_zano/api/model/get_wallet_info_result.dart';
import 'package:cw_zano/api/model/get_wallet_status_result.dart';
import 'package:cw_zano/api/model/zano_wallet_keys.dart';
import 'package:cw_zano/zano_balance.dart';
import 'package:cw_zano/zano_wallet.dart';
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart' as mobx;
int getCurrentHeight(int hWallet) {
final json = ApiCalls.getWalletStatus(hWallet: hWallet);
final walletStatus = GetWalletStatusResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
return walletStatus.currentWalletHeight;
}
int getNodeHeightSync(int hWallet) {
final json = ApiCalls.getWalletStatus(hWallet: hWallet);
final walletStatus = GetWalletStatusResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
return walletStatus.currentDaemonHeight;
}
class SyncListener {
SyncListener(this.onNewBlock, this.onNewTransaction)
: _cachedBlockchainHeight = 0,
_lastKnownBlockHeight = 0,
_initialSyncHeight = 0;
void Function(int, int, double) onNewBlock;
void Function() onNewTransaction;
Timer? _updateSyncInfoTimer;
int _cachedBlockchainHeight;
int _lastKnownBlockHeight;
int _initialSyncHeight;
// Future<int> getNodeHeightOrUpdate(int hWallet, int baseHeight) async {
// if (_cachedBlockchainHeight < baseHeight || _cachedBlockchainHeight == 0) {
// _cachedBlockchainHeight = await compute<int, int>(getNodeHeightSync, hWallet);
// }
// return _cachedBlockchainHeight;
// }
void start(ZanoWalletBase wallet, int hWallet) async {
_cachedBlockchainHeight = 0;
_lastKnownBlockHeight = 0;
_initialSyncHeight = 0;
_updateSyncInfoTimer ??= Timer.periodic(Duration(milliseconds: 1200), (_) async {
/**if (isNewTransactionExist()) {
onNewTransaction?.call();
}*/
var json = ApiCalls.getWalletStatus(hWallet: hWallet);
print('wallet status $json');
final status = GetWalletStatusResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
// You can call getWalletInfo ONLY if getWalletStatus returns NOT is in long refresh and wallet state is 2 (ready)
if (!status.isInLongRefresh && status.walletState == 2) {
final syncHeight = status.currentWalletHeight;
json = ApiCalls.getWalletInfo(hWallet);
print('wallet info $json');
final result = GetWalletInfoResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
wallet.seed = result.wiExtended.seed;
wallet.keys = ZanoWalletKeys(
privateSpendKey: result.wiExtended.spendPrivateKey,
privateViewKey: result.wiExtended.viewPrivateKey,
publicSpendKey: result.wiExtended.spendPublicKey,
publicViewKey: result.wiExtended.viewPublicKey,
);
final balance = result.wi.balances.first;
wallet.assetId = balance.assetInfo.assetId;
wallet.balance = mobx.ObservableMap.of({CryptoCurrency.zano: ZanoBalance(total: balance.total, unlocked: balance.unlocked)});
if (_initialSyncHeight <= 0) {
_initialSyncHeight = syncHeight;
}
final bchHeight = status.currentDaemonHeight;
if (_lastKnownBlockHeight == syncHeight) {
return;
}
_lastKnownBlockHeight = syncHeight;
final track = bchHeight - _initialSyncHeight;
final diff = track - (bchHeight - syncHeight);
final ptc = diff <= 0 ? 0.0 : diff / track;
final left = bchHeight - syncHeight;
if (syncHeight < 0 || left < 0) {
return;
}
// 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents;
onNewBlock.call(syncHeight, left, ptc);
}
});
}
void stop() => _updateSyncInfoTimer?.cancel();
}
SyncListener setListeners(void Function(int, int, double) onNewBlock, void Function() onNewTransaction) {
final listener = SyncListener(onNewBlock, onNewTransaction);
/**setListenerNative();*/
return listener;
}

View file

@ -0,0 +1,8 @@
class ZanoTransactionCreationException implements Exception {
ZanoTransactionCreationException(this.message);
final String message;
@override
String toString() => message;
}

View file

@ -7,83 +7,62 @@ import 'package:cw_zano/api/model/transfer_result.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/amount_converter.dart';
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_zano/api/api_calls.dart' as calls;
import 'package:cw_zano/zano_wallet.dart';
class PendingZanoTransaction with PendingTransaction {
PendingZanoTransaction(
{required this.zanoWallet,
required this.fee,
required this.intAmount,
//required this.stringAmount,
required this.hWallet,
required this.address,
required this.assetId,
required this.comment});
PendingZanoTransaction({
required this.zanoWallet,
required this.destinations,
required this.fee,
required this.comment,
});
final ZanoWalletBase zanoWallet;
final int hWallet;
final int intAmount;
//final String stringAmount;
final List<Destination> destinations;
final int fee;
final String address;
final String assetId;
final String comment;
final CryptoCurrency cryptoCurrency = CryptoCurrency.zano;
@override
String get id => transferResult != null ? transferResult!.txHash : '';
String get id => transferResult?.txHash ?? '';
@override
String get hex => '';
@override
String get amountFormatted {
return AmountConverter.amountIntToString(cryptoCurrency, intAmount);
}
String get amountFormatted => AmountConverter.amountIntToString(CryptoCurrency.zano, destinations.first.amount);
@override
String get feeFormatted => AmountConverter.amountIntToString(cryptoCurrency, fee);
String get feeFormatted => AmountConverter.amountIntToString(CryptoCurrency.zano, fee);
TransferResult? transferResult;
@override
Future<void> commit() async {
final params = TransferParams(
destinations: [
Destination(
amount: intAmount.toString(),
address: address,
assetId: assetId,
)
],
destinations: destinations,
fee: fee,
mixin: zanoMixin,
paymentId: '',
comment: comment,
pushPayer: false,
hideReceiver: false,
hideReceiver: true,
);
final result = await zanoWallet.invokeMethod(hWallet, 'transfer', params);
final result = await zanoWallet.invokeMethod('transfer', params);
final map = jsonDecode(result);
if (map['result'] != null && map['result']['result'] != null) {
transferResult = TransferResult.fromJson(
map['result']['result'] as Map<String, dynamic>,
);
await zanoWallet.fetchTransactions();
} else if (map['result'] != null && map['result']['error'] != null) {
final String code;
if (map['result']['error']['code'] is int) {
code = (map['result']['error']['code'] as int).toString();
} else if (map['result']['error']['code'] is String) {
code = map['result']['error']['code'] as String;
final resultMap = map['result'] as Map<String, dynamic>?;
if (resultMap != null) {
final transferResultMap = resultMap['result'] as Map<String, dynamic>?;
if (transferResultMap != null) {
transferResult = TransferResult.fromJson(transferResultMap);
print('transfer success hash ${transferResult!.txHash}');
await zanoWallet.fetchTransactions();
} else {
code = '';
final errorCode = resultMap['error']['code'];
final code = errorCode is int ? errorCode.toString() : errorCode as String? ?? '';
final message = resultMap['error']['message'] as String? ?? '';
print('transfer error $code $message');
throw TransferException(code, message);
}
final message = map['result']['error']['message'] as String;
print('transfer error $code $message');
throw TransferException(code, message);
}
}
}

View file

@ -1,9 +1,8 @@
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:cw_core/output_info.dart';
class ZanoTransactionCreationCredentials {
ZanoTransactionCreationCredentials(
{required this.outputs, required this.priority, required this.assetType});
class ZanoTransactionCredentials {
ZanoTransactionCredentials({required this.outputs, required this.priority, required this.assetType});
final List<OutputInfo> outputs;
final MoneroTransactionPriority priority;

View file

@ -5,6 +5,7 @@ import 'dart:io';
import 'dart:math';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_core/monero_wallet_utils.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/pathForWallet.dart';
@ -13,17 +14,19 @@ import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_zano/api/api_calls.dart' as calls;
import 'package:cw_zano/api/api_calls.dart';
import 'package:cw_zano/api/model/destination.dart';
import 'package:cw_zano/api/model/get_recent_txs_and_info_params.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/history.dart';
import 'package:cw_zano/api/model/store_result.dart';
import 'package:cw_zano/api/model/zano_wallet_keys.dart';
import 'package:cw_zano/api/wallet.dart' as zano_wallet;
import 'package:cw_zano/api/zano_api.dart';
import 'package:cw_zano/exceptions/zano_transaction_creation_exception.dart';
import 'package:cw_zano/pending_zano_transaction.dart';
import 'package:cw_zano/zano_balance.dart';
import 'package:cw_zano/zano_transaction_creation_credentials.dart';
import 'package:cw_zano/zano_transaction_credentials.dart';
import 'package:cw_zano/zano_transaction_history.dart';
import 'package:cw_zano/zano_transaction_info.dart';
import 'package:cw_zano/zano_wallet_addresses.dart';
@ -62,7 +65,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
}
List<History> history = [];
String assetId = '';
String defaultAsssetId = '';
static const int _autoSaveInterval = 30;
static const _statusDelivered = 'delivered';
@ -85,8 +88,12 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
@override
ZanoWalletKeys keys = ZanoWalletKeys(privateSpendKey: '', privateViewKey: '', publicSpendKey: '', publicViewKey: '');
zano_wallet.SyncListener? _listener;
//zano_wallet.SyncListener? _listener;
/**ReactionDisposer? _onAccountChangeReaction;*/
Timer? _updateSyncInfoTimer;
int _cachedBlockchainHeight = 0;
int _lastKnownBlockHeight = 0;
int _initialSyncHeight = 0;
bool _isTransactionUpdating;
bool _hasSyncAfterStartup;
Timer? _autoSaveTimer;
@ -104,17 +111,9 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
await walletAddresses.updateAddress(address);
///balance.addAll(getZanoBalance(/**accountIndex: walletAddresses.account?.id ?? 0*/));
_setListeners();
//_setListeners();
await updateTransactions();
if (walletInfo.isRecovery) {
debugPrint('setRecoveringFromSeed isRecovery ${walletInfo.isRecovery}');
if (zano_wallet.getCurrentHeight(hWallet) <= 1) {
debugPrint('setRefreshFromBlockHeight height ${walletInfo.restoreHeight}');
}
}
_autoSaveTimer = Timer.periodic(Duration(seconds: _autoSaveInterval), (_) async => await save());
}
@ -123,7 +122,8 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
@override
void close() {
_listener?.stop();
_updateSyncInfoTimer?.cancel();
//_listener?.stop();
/**_onAccountChangeReaction?.reaction.dispose();*/
_autoSaveTimer?.cancel();
}
@ -151,15 +151,58 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
@override
Future<void> startSync() async {
try {
_setInitialHeight();
} catch (_) {}
try {
syncStatus = AttemptingSyncStatus();
debugPrint("startRefresh");
_setListeners();
_listener?.start(this, hWallet);
_cachedBlockchainHeight = 0;
_lastKnownBlockHeight = 0;
_initialSyncHeight = 0;
_updateSyncInfoTimer ??= Timer.periodic(Duration(milliseconds: 1200), (_) async {
/**if (isNewTransactionExist()) {
onNewTransaction?.call();
}*/
GetWalletStatusResult status = getWalletStatus();
// You can call getWalletInfo ONLY if getWalletStatus returns NOT is in long refresh and wallet state is 2 (ready)
if (!status.isInLongRefresh && status.walletState == 2) {
final syncHeight = status.currentWalletHeight;
GetWalletInfoResult result = getWalletInfo();
seed = result.wiExtended.seed;
keys = ZanoWalletKeys(
privateSpendKey: result.wiExtended.spendPrivateKey,
privateViewKey: result.wiExtended.viewPrivateKey,
publicSpendKey: result.wiExtended.spendPublicKey,
publicViewKey: result.wiExtended.viewPublicKey,
);
final _balance = result.wi.balances.first;
defaultAsssetId = _balance.assetInfo.assetId;
balance = ObservableMap.of({CryptoCurrency.zano: ZanoBalance(total: _balance.total, unlocked: _balance.unlocked)});
if (_initialSyncHeight <= 0) {
_initialSyncHeight = syncHeight;
}
final bchHeight = status.currentDaemonHeight;
if (_lastKnownBlockHeight == syncHeight) {
return;
}
_lastKnownBlockHeight = syncHeight;
final track = bchHeight - _initialSyncHeight;
final diff = track - (bchHeight - syncHeight);
final ptc = diff <= 0 ? 0.0 : diff / track;
final left = bchHeight - syncHeight;
if (syncHeight < 0 || left < 0) {
return;
}
// 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents;
_onNewBlock.call(syncHeight, left, ptc);
}
});
} catch (e) {
syncStatus = FailedSyncStatus();
print(e);
@ -169,82 +212,54 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
@override
Future<PendingTransaction> createTransaction(Object credentials) async {
final creds = credentials as ZanoTransactionCreationCredentials;
final output = creds.outputs.first;
final address = output.isParsedAddress && (output.extractedAddress?.isNotEmpty ?? false) ? output.extractedAddress! : output.address;
final stringAmount = output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.');
final fee = calculateEstimatedFee(creds.priority);
final intAmount = (double.parse(stringAmount!) * pow(10, 12)).toInt();
final transaction = PendingZanoTransaction(fee: fee, intAmount: intAmount, hWallet: hWallet, address: address, assetId: assetId, comment: output.note ?? '', zanoWallet: this);
return transaction;
/*final _credentials = credentials as ZanoTransactionCreationCredentials;
final outputs = _credentials.outputs;
final creds = credentials as ZanoTransactionCredentials;
final outputs = creds.outputs;
final hasMultiDestination = outputs.length > 1;
final assetType =
CryptoCurrency.fromString(_credentials.assetType.toLowerCase());
final balances = getZanoBalance(/*accountIndex: walletAddresses.account!.id*/);
final unlockedBalance = balances[assetType]!.unlockedBalance;
PendingTransactionDescription pendingTransactionDescription;
if (!(syncStatus is SyncedSyncStatus)) {
throw ZanoTransactionCreationException('The wallet is not synced.');
}
final unlockedBalance = balance[CryptoCurrency.zano]?.unlocked ?? 0;
final fee = calculateEstimatedFee(creds.priority);
late List<Destination> destinations;
if (hasMultiDestination) {
if (outputs.any(
(item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
throw ZanoTransactionCreationException(
'You do not have enough coins to send this amount.');
if (outputs.any((output) => output.sendAll || (output.formattedCryptoAmount ?? 0) <= 0)) {
throw ZanoTransactionCreationException("You don't have enough coins.");
}
final int totalAmount = outputs.fold(
0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0));
if (unlockedBalance < totalAmount) {
final int totalAmount = outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0));
if (totalAmount + fee > unlockedBalance) {
throw ZanoTransactionCreationException(
'You do not have enough coins to send this amount.');
"You don't have enough coins (required: ${moneroAmountToString(amount: totalAmount + fee)}, unlocked ${moneroAmountToString(amount: unlockedBalance)}).");
}
final zanoOutputs = outputs
.map((output) => ZanoOutput(
address: output.address,
amount: output.cryptoAmount!.replaceAll(',', '.')))
destinations = outputs
.map((output) => Destination(
amount: output.formattedCryptoAmount ?? 0,
address: output.isParsedAddress ? output.extractedAddress! : output.address,
assetId: defaultAsssetId,
))
.toList();
pendingTransactionDescription =
await transaction_history.createTransactionMultDest(
outputs: zanoOutputs,
priorityRaw: _credentials.priority.serialize());
} else {
final output = outputs.first;
final address = output.isParsedAddress &&
(output.extractedAddress?.isNotEmpty ?? false)
? output.extractedAddress!
: output.address;
final amount =
output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.');
final int? formattedAmount =
output.sendAll ? null : output.formattedCryptoAmount;
if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
(formattedAmount == null && unlockedBalance <= 0)) {
final formattedBalance = moneroAmountToString(amount: unlockedBalance);
throw ZanoTransactionCreationException(
'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
late int amount;
if (output.sendAll) {
amount = unlockedBalance - fee;
} else {
amount = output.formattedCryptoAmount!;
}
pendingTransactionDescription =
await transaction_history.createTransaction(
address: address,
assetType: _credentials.assetType,
amount: amount,
priorityRaw: _credentials.priority.serialize());
if (amount + fee > unlockedBalance) {
throw ZanoTransactionCreationException(
"You don't have enough coins (required: ${moneroAmountToString(amount: amount + fee)}, unlocked ${moneroAmountToString(amount: unlockedBalance)}).");
}
destinations = [
Destination(
amount: amount,
address: output.isParsedAddress ? output.extractedAddress! : output.address,
assetId: defaultAsssetId,
)
];
}
return PendingZanoTransaction(pendingTransactionDescription, assetType);*/
return PendingZanoTransaction(
zanoWallet: this,
destinations: destinations,
fee: fee,
comment: outputs.first.note ?? '',
);
}
@override
@ -265,7 +280,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
Future<void> store() async {
try {
final json = await invokeMethod(hWallet, 'store', '{}');
final json = await invokeMethod('store', '{}');
final map = jsonDecode(json) as Map<String, dynamic>;
if (map['result'] == null || map['result']['result'] == null) {
throw 'store empty response';
@ -326,7 +341,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
Future<void> _refreshTransactions() async {
try {
final result = await invokeMethod(hWallet, 'get_recent_txs_and_info', GetRecentTxsAndInfoParams(offset: 0, count: 30));
final result = await invokeMethod('get_recent_txs_and_info', GetRecentTxsAndInfoParams(offset: 0, count: 30));
final map = jsonDecode(result) as Map<String, dynamic>?;
if (map == null) {
print('get_recent_txs_and_info empty response');
@ -396,31 +411,14 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
// .map((row) => ZanoTransactionInfo.fromRow(row))
// .toList();
void _setListeners() {
_listener?.stop();
_listener = zano_wallet.setListeners(_onNewBlock, _onNewTransaction);
}
// void _setListeners() {
// _listener?.stop();
// _listener = zano_wallet.setListeners(_onNewBlock, _onNewTransaction);
// }
void _setInitialHeight() {
if (walletInfo.isRecovery) {
return;
}
final currentHeight = zano_wallet.getCurrentHeight(hWallet);
if (currentHeight <= 1) {
final height = _getHeightByDate(walletInfo.date);
debugPrint('setRecoveringFromSeed isRecovery true');
debugPrint('setRefreshFromBlockHeight height $height');
}
}
int _getHeightByDate(DateTime date) {
return 0;
}
void _askForUpdateBalance() {
debugPrint('askForUpdateBalance');
debugPrint('askForUpdateBalance'); // TODO: remove, also remove this method completely
}
Future<void> _askForUpdateTransactionHistory() async => await updateTransactions();
@ -459,7 +457,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
try {
await _askForUpdateTransactionHistory();
_askForUpdateBalance();
await Future<void>.delayed(Duration(seconds: 1));
await Future<void>.delayed(Duration(seconds: 1)); // TODO: ???
} catch (e) {
print(e.toString());
}
@ -484,7 +482,7 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
return str;
}
Future<String> invokeMethod(int hWallet, String methodName, Object params) async {
Future<String> invokeMethod(String methodName, Object params) async {
var invokeResult = ApiCalls.asyncCall(methodName: 'invoke', hWallet: hWallet, params: '{"method": "$methodName","params": ${jsonEncode(params)}}');
var map = jsonDecode(invokeResult) as Map<String, dynamic>;
int attempts = 0;
@ -501,4 +499,18 @@ abstract class ZanoWalletBase extends WalletBase<ZanoBalance, ZanoTransactionHis
}
return invokeResult;
}
GetWalletInfoResult getWalletInfo() {
final json = ApiCalls.getWalletInfo(hWallet);
print('wallet info $json'); // TODO: remove
final result = GetWalletInfoResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
return result;
}
GetWalletStatusResult getWalletStatus() {
final json = ApiCalls.getWalletStatus(hWallet: hWallet);
print('wallet status $json'); // TODO: remove
final status = GetWalletStatusResult.fromJson(jsonDecode(json) as Map<String, dynamic>);
return status;
}
}

View file

@ -24,13 +24,11 @@ import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
class ZanoNewWalletCredentials extends WalletCredentials {
ZanoNewWalletCredentials({required String name, String? password})
: super(name: name, password: password);
ZanoNewWalletCredentials({required String name, String? password}) : super(name: name, password: password);
}
class ZanoRestoreWalletFromSeedCredentials extends WalletCredentials {
ZanoRestoreWalletFromSeedCredentials(
{required String name, required String password, required int height, required this.mnemonic})
ZanoRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required this.mnemonic})
: super(name: name, password: password, height: height);
final String mnemonic;
@ -38,13 +36,7 @@ class ZanoRestoreWalletFromSeedCredentials extends WalletCredentials {
class ZanoRestoreWalletFromKeysCredentials extends WalletCredentials {
ZanoRestoreWalletFromKeysCredentials(
{required String name,
required String password,
required this.language,
required this.address,
required this.viewKey,
required this.spendKey,
required int height})
{required String name, required String password, required this.language, required this.address, required this.viewKey, required this.spendKey, required int height})
: super(name: name, password: password, height: height);
final String language;
@ -53,14 +45,12 @@ class ZanoRestoreWalletFromKeysCredentials extends WalletCredentials {
final String spendKey;
}
class ZanoWalletService extends WalletService<ZanoNewWalletCredentials,
ZanoRestoreWalletFromSeedCredentials, ZanoRestoreWalletFromKeysCredentials> {
class ZanoWalletService extends WalletService<ZanoNewWalletCredentials, ZanoRestoreWalletFromSeedCredentials, ZanoRestoreWalletFromKeysCredentials> {
ZanoWalletService(this.walletInfoSource);
final Box<WalletInfo> walletInfoSource;
static bool walletFilesExist(String path) =>
!File(path).existsSync() && !File('$path.keys').existsSync();
static bool walletFilesExist(String path) => !File(path).existsSync() && !File('$path.keys').existsSync();
int hWallet = 0;
@ -109,8 +99,7 @@ class ZanoWalletService extends WalletService<ZanoNewWalletCredentials,
await repairOldAndroidWallet(name);
}
final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
final walletInfo = walletInfoSource.values.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
final wallet = ZanoWallet(walletInfo);
await wallet.connectToNode(node: Node());
final result = wallet.loadWallet(path, password);
@ -132,9 +121,8 @@ class ZanoWalletService extends WalletService<ZanoNewWalletCredentials,
wallet.hWallet = hWallet;
wallet.walletAddresses.address = result.wi.address;
final balance = result.wi.balances.first;
wallet.assetId = balance.assetInfo.assetId;
wallet.balance = ObservableMap.of(
{CryptoCurrency.zano: ZanoBalance(total: balance.total, unlocked: balance.unlocked)});
wallet.defaultAsssetId = balance.assetInfo.assetId;
wallet.balance = ObservableMap.of({CryptoCurrency.zano: ZanoBalance(total: balance.total, unlocked: balance.unlocked)});
if (result.recentHistory.history != null) {
wallet.history = result.recentHistory.history!;
}
@ -150,15 +138,13 @@ class ZanoWalletService extends WalletService<ZanoNewWalletCredentials,
await file.delete(recursive: true);
}
final walletInfo = walletInfoSource.values
.firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
final walletInfo = walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
await walletInfoSource.delete(walletInfo.key);
}
@override
Future<void> rename(String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
final currentWalletInfo = walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
final currentWallet = ZanoWallet(currentWalletInfo);
await currentWallet.renameWalletFiles(newName);
@ -184,8 +170,7 @@ class ZanoWalletService extends WalletService<ZanoNewWalletCredentials,
final result = ApiCalls.restoreWalletFromSeed(path: path, password: credentials.password!, seed: credentials.mnemonic);
final map = json.decode(result) as Map<String, dynamic>;
if (map['result'] != null) {
final createWalletResult =
CreateWalletResult.fromJson(map['result'] as Map<String, dynamic>);
final createWalletResult = CreateWalletResult.fromJson(map['result'] as Map<String, dynamic>);
_parseCreateWalletResult(createWalletResult, wallet);
await wallet.store();
await wallet.init(createWalletResult.wi.address);
@ -200,7 +185,7 @@ class ZanoWalletService extends WalletService<ZanoNewWalletCredentials,
}
throw RestoreFromSeedException(code, message);
}
throw RestoreFromSeedException('', '');
throw RestoreFromSeedException('', '');
} catch (e) {
// TODO: Implement Exception for wallet list service.
print('ZanoWalletsManager Error: $e');

View file

@ -113,36 +113,17 @@ class CWZano extends Zano {
@override
WalletCredentials createZanoRestoreWalletFromKeysCredentials(
{required String name,
required String spendKey,
required String viewKey,
required String address,
required String password,
required String language,
required int height}) {
return ZanoRestoreWalletFromKeysCredentials(
name: name,
spendKey: spendKey,
viewKey: viewKey,
address: address,
password: password,
language: language,
height: height);
{required String name, required String spendKey, required String viewKey, required String address, required String password, required String language, required int height}) {
return ZanoRestoreWalletFromKeysCredentials(name: name, spendKey: spendKey, viewKey: viewKey, address: address, password: password, language: language, height: height);
}
@override
WalletCredentials createZanoRestoreWalletFromSeedCredentials(
{required String name,
required String password,
required int height,
required String mnemonic}) {
return ZanoRestoreWalletFromSeedCredentials(
name: name, password: password, height: height, mnemonic: mnemonic);
WalletCredentials createZanoRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic}) {
return ZanoRestoreWalletFromSeedCredentials(name: name, password: password, height: height, mnemonic: mnemonic);
}
@override
WalletCredentials createZanoNewWalletCredentials(
{required String name, String? password}) {
WalletCredentials createZanoNewWalletCredentials({required String name, String? password}) {
return ZanoNewWalletCredentials(name: name, password: password);
}
@ -159,11 +140,8 @@ class CWZano extends Zano {
}
@override
Object createZanoTransactionCreationCredentials(
{required List<Output> outputs,
required TransactionPriority priority,
required String assetType}) {
return ZanoTransactionCreationCredentials(
Object createZanoTransactionCreationCredentials({required List<Output> outputs, required TransactionPriority priority, required String assetType}) {
return ZanoTransactionCredentials(
outputs: outputs
.map((out) => OutputInfo(
fiatAmount: out.fiatAmount,

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/utils/language_list.dart';
import 'package:cw_zano/zano_transaction_credentials.dart';
import 'package:mobx/mobx.dart';
import 'package:flutter/foundation.dart';
import 'package:cw_core/wallet_credentials.dart';
@ -12,15 +13,12 @@ import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:hive/hive.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/get_height_by_date.dart';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:cw_zano/zano_wallet_service.dart';
import 'package:cw_zano/zano_wallet.dart';
import 'package:cw_zano/zano_transaction_info.dart';
import 'package:cw_zano/zano_transaction_history.dart';
import 'package:cw_zano/mnemonics/english.dart';
import 'package:cw_zano/zano_transaction_creation_credentials.dart';
part 'cw_zano.dart';