diff --git a/cw_monero/lib/api/wallet.dart b/cw_monero/lib/api/wallet.dart index 51bd995ce..e213f13c3 100644 --- a/cw_monero/lib/api/wallet.dart +++ b/cw_monero/lib/api/wallet.dart @@ -43,6 +43,11 @@ String getSeed() { return legacy; } +String getSeedLegacy() { + final legacy = monero.Wallet_seed(wptr!, seedOffset: ''); + return legacy; +} + String getAddress({int accountIndex = 0, int addressIndex = 1}) => monero.Wallet_address(wptr!, accountIndex: accountIndex, addressIndex: addressIndex); diff --git a/cw_monero/lib/monero_wallet.dart b/cw_monero/lib/monero_wallet.dart index 9b47b5a9b..80108271d 100644 --- a/cw_monero/lib/monero_wallet.dart +++ b/cw_monero/lib/monero_wallet.dart @@ -19,6 +19,7 @@ import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_info.dart'; +import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/coins_info.dart'; import 'package:cw_monero/api/monero_output.dart'; import 'package:cw_monero/api/structs/pending_transaction.dart'; @@ -46,10 +47,11 @@ const MIN_RESTORE_HEIGHT = 1000; class MoneroWallet = MoneroWalletBase with _$MoneroWallet; -abstract class MoneroWalletBase - extends WalletBase with Store { +abstract class MoneroWalletBase extends WalletBase with Store { MoneroWalletBase( - {required WalletInfo walletInfo, required Box unspentCoinsInfo}) + {required WalletInfo walletInfo, + required Box unspentCoinsInfo}) : balance = ObservableMap.of({ CryptoCurrency.xmr: MoneroBalance( fullBalance: monero_wallet.getFullBalance(accountIndex: 0), @@ -65,13 +67,16 @@ abstract class MoneroWalletBase transactionHistory = MoneroTransactionHistory(); walletAddresses = MoneroWalletAddresses(walletInfo, transactionHistory); - _onAccountChangeReaction = reaction((_) => walletAddresses.account, (Account? account) { + _onAccountChangeReaction = + reaction((_) => walletAddresses.account, (Account? account) { if (account == null) return; - balance = ObservableMap.of({ + balance = ObservableMap.of({ currency: MoneroBalance( fullBalance: monero_wallet.getFullBalance(accountIndex: account.id), - unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: account.id)) + unlockedBalance: + monero_wallet.getUnlockedBalance(accountIndex: account.id)) }); _updateSubAddress(isEnabledAutoGenerateSubaddress, account: account); _askForUpdateTransactionHistory(); @@ -105,6 +110,10 @@ abstract class MoneroWalletBase @override String get seed => monero_wallet.getSeed(); + String get seedLegacy { + monero.Wallet_setSeedLanguage(wptr!, language: "English"); + return monero_wallet.getSeedLegacy(); + } @override MoneroWalletKeys get keys => MoneroWalletKeys( @@ -113,7 +122,8 @@ abstract class MoneroWalletBase publicSpendKey: monero_wallet.getPublicSpendKey(), publicViewKey: monero_wallet.getPublicViewKey()); - int? get restoreHeight => transactionHistory.transactions.values.firstOrNull?.height; + int? get restoreHeight => + transactionHistory.transactions.values.firstOrNull?.height; monero_wallet.SyncListener? _listener; ReactionDisposer? _onAccountChangeReaction; @@ -124,11 +134,13 @@ abstract class MoneroWalletBase Future init() async { await walletAddresses.init(); - balance = ObservableMap.of({ + balance = ObservableMap.of({ currency: MoneroBalance( - fullBalance: monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id), - unlockedBalance: - monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id)) + fullBalance: monero_wallet.getFullBalance( + accountIndex: walletAddresses.account!.id), + unlockedBalance: monero_wallet.getUnlockedBalance( + accountIndex: walletAddresses.account!.id)) }); _setListeners(); await updateTransactions(); @@ -137,12 +149,13 @@ abstract class MoneroWalletBase monero_wallet.setRecoveringFromSeed(isRecovery: walletInfo.isRecovery); if (monero_wallet.getCurrentHeight() <= 1) { - monero_wallet.setRefreshFromBlockHeight(height: walletInfo.restoreHeight); + monero_wallet.setRefreshFromBlockHeight( + height: walletInfo.restoreHeight); } } - _autoSaveTimer = - Timer.periodic(Duration(seconds: _autoSaveInterval), (_) async => await save()); + _autoSaveTimer = Timer.periodic( + Duration(seconds: _autoSaveInterval), (_) async => await save()); } @override @@ -214,8 +227,8 @@ abstract class MoneroWalletBase final inputs = []; final outputs = _credentials.outputs; final hasMultiDestination = outputs.length > 1; - final unlockedBalance = - monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id); + final unlockedBalance = monero_wallet.getUnlockedBalance( + accountIndex: walletAddresses.account!.id); var allInputsAmount = 0; PendingTransactionDescription pendingTransactionDescription; @@ -237,16 +250,20 @@ abstract class MoneroWalletBase final spendAllCoins = inputs.length == unspentCoins.length; if (hasMultiDestination) { - if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) { - throw MoneroTransactionCreationException('You do not have enough XMR to send this amount.'); + if (outputs.any( + (item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) { + throw MoneroTransactionCreationException( + 'You do not have enough XMR to send this amount.'); } - final int totalAmount = - outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)); + final int totalAmount = outputs.fold( + 0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)); - final estimatedFee = calculateEstimatedFee(_credentials.priority, totalAmount); + final estimatedFee = + calculateEstimatedFee(_credentials.priority, totalAmount); if (unlockedBalance < totalAmount) { - throw MoneroTransactionCreationException('You do not have enough XMR to send this amount.'); + throw MoneroTransactionCreationException( + 'You do not have enough XMR to send this amount.'); } if (!spendAllCoins && (allInputsAmount < totalAmount + estimatedFee)) { @@ -254,22 +271,28 @@ abstract class MoneroWalletBase } final moneroOutputs = outputs.map((output) { - final outputAddress = output.isParsedAddress ? output.extractedAddress : output.address; + final outputAddress = + output.isParsedAddress ? output.extractedAddress : output.address; return MoneroOutput( - address: outputAddress!, amount: output.cryptoAmount!.replaceAll(',', '.')); + address: outputAddress!, + amount: output.cryptoAmount!.replaceAll(',', '.')); }).toList(); - pendingTransactionDescription = await transaction_history.createTransactionMultDest( - outputs: moneroOutputs, - priorityRaw: _credentials.priority.serialize(), - accountIndex: walletAddresses.account!.id, - preferredInputs: inputs); + pendingTransactionDescription = + await transaction_history.createTransactionMultDest( + outputs: moneroOutputs, + priorityRaw: _credentials.priority.serialize(), + accountIndex: walletAddresses.account!.id, + preferredInputs: inputs); } else { final output = outputs.first; - final address = output.isParsedAddress ? output.extractedAddress : output.address; - final amount = output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.'); - final formattedAmount = output.sendAll ? null : output.formattedCryptoAmount; + final address = + output.isParsedAddress ? output.extractedAddress : output.address; + final amount = + output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.'); + final formattedAmount = + output.sendAll ? null : output.formattedCryptoAmount; if ((formattedAmount != null && unlockedBalance < formattedAmount) || (formattedAmount == null && unlockedBalance <= 0)) { @@ -279,19 +302,22 @@ abstract class MoneroWalletBase 'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.'); } - final estimatedFee = calculateEstimatedFee(_credentials.priority, formattedAmount); + final estimatedFee = + calculateEstimatedFee(_credentials.priority, formattedAmount); if (!spendAllCoins && - ((formattedAmount != null && allInputsAmount < (formattedAmount + estimatedFee)) || + ((formattedAmount != null && + allInputsAmount < (formattedAmount + estimatedFee)) || formattedAmount == null)) { throw MoneroTransactionNoInputsException(inputs.length); } - pendingTransactionDescription = await transaction_history.createTransaction( - address: address!, - amount: amount, - priorityRaw: _credentials.priority.serialize(), - accountIndex: walletAddresses.account!.id, - preferredInputs: inputs); + pendingTransactionDescription = + await transaction_history.createTransaction( + address: address!, + amount: amount, + priorityRaw: _credentials.priority.serialize(), + accountIndex: walletAddresses.account!.id, + preferredInputs: inputs); } return PendingMoneroTransaction(pendingTransactionDescription); @@ -349,18 +375,17 @@ abstract class MoneroWalletBase final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.address; await Isolate.run(() { monero.WalletManager_closeWallet( - Pointer.fromAddress(wmaddr), - Pointer.fromAddress(waddr), - true - ); + Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true); }); openedWalletsByPath.remove("$currentWalletDirPath/$name"); print("wallet closed"); } try { // -- rename the waller folder -- - final currentWalletDir = Directory(await pathForWalletDir(name: name, type: type)); - final newWalletDirPath = await pathForWalletDir(name: newWalletName, type: type); + final currentWalletDir = + Directory(await pathForWalletDir(name: name, type: type)); + final newWalletDirPath = + await pathForWalletDir(name: newWalletName, type: type); await currentWalletDir.rename(newWalletDirPath); // -- use new waller folder to rename files with old names still -- @@ -370,7 +395,8 @@ abstract class MoneroWalletBase final currentKeysFile = File('$renamedWalletPath.keys'); final currentAddressListFile = File('$renamedWalletPath.address.txt'); - final newWalletPath = await pathForWallet(name: newWalletName, type: type); + final newWalletPath = + await pathForWallet(name: newWalletName, type: type); if (currentCacheFile.existsSync()) { await currentCacheFile.rename(newWalletPath); @@ -390,7 +416,8 @@ abstract class MoneroWalletBase final currentKeysFile = File('$currentWalletPath.keys'); final currentAddressListFile = File('$currentWalletPath.address.txt'); - final newWalletPath = await pathForWallet(name: newWalletName, type: type); + final newWalletPath = + await pathForWallet(name: newWalletName, type: type); // Copies current wallet files into new wallet name's dir and files if (currentCacheFile.existsSync()) { @@ -409,7 +436,8 @@ abstract class MoneroWalletBase } @override - Future changePassword(String password) async => monero_wallet.setPasswordSync(password); + Future changePassword(String password) async => + monero_wallet.setPasswordSync(password); Future getNodeHeight() async => monero_wallet.getNodeHeight(); @@ -454,7 +482,8 @@ abstract class MoneroWalletBase monero.CoinsInfo_unlocked(coin), ); if (unspent.hash.isNotEmpty) { - unspent.isChange = transaction_history.getTransaction(unspent.hash) == 1; + unspent.isChange = + transaction_history.getTransaction(unspent.hash) == 1; } unspentCoins.add(unspent); } @@ -516,13 +545,15 @@ abstract class MoneroWalletBase Future _refreshUnspentCoinsInfo() async { try { final List keys = []; - final currentWalletUnspentCoins = unspentCoinsInfo.values.where((element) => - element.walletId.contains(id) && element.accountIndex == walletAddresses.account!.id); + final currentWalletUnspentCoins = unspentCoinsInfo.values.where( + (element) => + element.walletId.contains(id) && + element.accountIndex == walletAddresses.account!.id); if (currentWalletUnspentCoins.isNotEmpty) { currentWalletUnspentCoins.forEach((element) { - final existUnspentCoins = - unspentCoins.where((coin) => element.keyImage!.contains(coin.keyImage!)); + final existUnspentCoins = unspentCoins + .where((coin) => element.keyImage!.contains(coin.keyImage!)); if (existUnspentCoins.isEmpty) { keys.add(element.key); @@ -539,13 +570,15 @@ abstract class MoneroWalletBase } String getTransactionAddress(int accountIndex, int addressIndex) => - monero_wallet.getAddress(accountIndex: accountIndex, addressIndex: addressIndex); + monero_wallet.getAddress( + accountIndex: accountIndex, addressIndex: addressIndex); @override Future> fetchTransactions() async { transaction_history.refreshTransactions(); return _getAllTransactionsOfAccount(walletAddresses.account?.id) - .fold>({}, + .fold>( + {}, (Map acc, MoneroTransactionInfo tx) { acc[tx.id] = tx; return acc; @@ -573,28 +606,31 @@ abstract class MoneroWalletBase String getSubaddressLabel(int accountIndex, int addressIndex) => monero_wallet.getSubaddressLabel(accountIndex, addressIndex); - List _getAllTransactionsOfAccount(int? accountIndex) => transaction_history - .getAllTransactions() - .map((row) => MoneroTransactionInfo( - row.hash, - row.blockheight, - row.isSpend ? TransactionDirection.outgoing : TransactionDirection.incoming, - row.timeStamp, - row.isPending, - row.amount, - row.accountIndex, - 0, - row.fee, - row.confirmations, - - )..additionalInfo = { - 'key': row.key, - 'accountIndex': row.accountIndex, - 'addressIndex': row.addressIndex - }, - ) - .where((element) => element.accountIndex == (accountIndex ?? 0)) - .toList(); + List _getAllTransactionsOfAccount(int? accountIndex) => + transaction_history + .getAllTransactions() + .map( + (row) => MoneroTransactionInfo( + row.hash, + row.blockheight, + row.isSpend + ? TransactionDirection.outgoing + : TransactionDirection.incoming, + row.timeStamp, + row.isPending, + row.amount, + row.accountIndex, + 0, + row.fee, + row.confirmations, + )..additionalInfo = { + 'key': row.key, + 'accountIndex': row.accountIndex, + 'addressIndex': row.addressIndex + }, + ) + .where((element) => element.accountIndex == (accountIndex ?? 0)) + .toList(); void _setListeners() { _listener?.stop(); @@ -632,7 +668,8 @@ abstract class MoneroWalletBase } int _getHeightDistance(DateTime date) { - final distance = DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch; + final distance = + DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch; final daysTmp = (distance / 86400).round(); final days = daysTmp < 1 ? 1 : daysTmp; @@ -660,22 +697,27 @@ abstract class MoneroWalletBase balance[currency]!.unlockedBalance != unlockedBalance || balance[currency]!.frozenBalance != frozenBalance) { balance[currency] = MoneroBalance( - fullBalance: fullBalance, unlockedBalance: unlockedBalance, frozenBalance: frozenBalance); + fullBalance: fullBalance, + unlockedBalance: unlockedBalance, + frozenBalance: frozenBalance); } } - Future _askForUpdateTransactionHistory() async => await updateTransactions(); + Future _askForUpdateTransactionHistory() async => + await updateTransactions(); - int _getFullBalance() => monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id); + int _getFullBalance() => + monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id); - int _getUnlockedBalance() => - monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id); + int _getUnlockedBalance() => monero_wallet.getUnlockedBalance( + accountIndex: walletAddresses.account!.id); int _getFrozenBalance() { var frozenBalance = 0; for (var coin in unspentCoinsInfo.values.where((element) => - element.walletId == id && element.accountIndex == walletAddresses.account!.id)) { + element.walletId == id && + element.accountIndex == walletAddresses.account!.id)) { if (coin.isFrozen) frozenBalance += coin.value; } diff --git a/cw_wownero/lib/api/wallet.dart b/cw_wownero/lib/api/wallet.dart index 6be7a6927..0e3a7b2c4 100644 --- a/cw_wownero/lib/api/wallet.dart +++ b/cw_wownero/lib/api/wallet.dart @@ -15,15 +15,17 @@ int getSyncingHeight() { } bool isNeededToRefresh() { - final ret = wownero.WOWNERO_cw_WalletListener_isNeedToRefresh(getWlptr()); - wownero.WOWNERO_cw_WalletListener_resetNeedToRefresh(getWlptr()); - return ret; + // final ret = wownero.WOWNERO_cw_WalletListener_isNeedToRefresh(getWlptr()); + // wownero.WOWNERO_cw_WalletListener_resetNeedToRefresh(getWlptr()); + return true; } bool isNewTransactionExist() { - final ret = wownero.WOWNERO_cw_WalletListener_isNewTransactionExist(getWlptr()); - wownero.WOWNERO_cw_WalletListener_resetIsNewTransactionExist(getWlptr()); - return ret; + // final ret = + // wownero.WOWNERO_cw_WalletListener_isNewTransactionExist(getWlptr()); + // wownero.WOWNERO_cw_WalletListener_resetIsNewTransactionExist(getWlptr()); + // NOTE: I don't know why wownero is being funky, but + return true; } String getFilename() => wownero.Wallet_filename(wptr!); @@ -43,6 +45,16 @@ String getSeed() { return legacy; } +String getSeedLegacy() { + final legacy = wownero.Wallet_seed(wptr!, seedOffset: ''); + print("seed: $legacy"); + if (wownero.Wallet_status(wptr!) != 0) { + print("error"); + return wownero.Wallet_errorString(wptr!); + } + return legacy; +} + String getAddress({int accountIndex = 0, int addressIndex = 1}) => wownero.Wallet_address(wptr!, accountIndex: accountIndex, addressIndex: addressIndex); diff --git a/cw_wownero/lib/wownero_wallet.dart b/cw_wownero/lib/wownero_wallet.dart index b78114207..c4fed1ce9 100644 --- a/cw_wownero/lib/wownero_wallet.dart +++ b/cw_wownero/lib/wownero_wallet.dart @@ -5,8 +5,6 @@ import 'dart:isolate'; import 'package:cw_core/account.dart'; import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/wownero_amount_format.dart'; -import 'package:cw_core/wownero_balance.dart'; import 'package:cw_core/monero_transaction_priority.dart'; import 'package:cw_core/monero_wallet_keys.dart'; import 'package:cw_core/monero_wallet_utils.dart'; @@ -19,20 +17,23 @@ import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_info.dart'; +import 'package:cw_core/wownero_amount_format.dart'; +import 'package:cw_core/wownero_balance.dart'; +import 'package:cw_wownero/api/account_list.dart'; import 'package:cw_wownero/api/coins_info.dart'; -import 'package:cw_wownero/api/wownero_output.dart'; import 'package:cw_wownero/api/structs/pending_transaction.dart'; import 'package:cw_wownero/api/transaction_history.dart' as transaction_history; import 'package:cw_wownero/api/wallet.dart' as wownero_wallet; import 'package:cw_wownero/api/wallet_manager.dart'; +import 'package:cw_wownero/api/wownero_output.dart'; import 'package:cw_wownero/exceptions/wownero_transaction_creation_exception.dart'; import 'package:cw_wownero/exceptions/wownero_transaction_no_inputs_exception.dart'; +import 'package:cw_wownero/pending_wownero_transaction.dart'; import 'package:cw_wownero/wownero_transaction_creation_credentials.dart'; import 'package:cw_wownero/wownero_transaction_history.dart'; import 'package:cw_wownero/wownero_transaction_info.dart'; import 'package:cw_wownero/wownero_unspent.dart'; import 'package:cw_wownero/wownero_wallet_addresses.dart'; -import 'package:cw_wownero/pending_wownero_transaction.dart'; import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; @@ -46,10 +47,11 @@ const MIN_RESTORE_HEIGHT = 1000; class WowneroWallet = WowneroWalletBase with _$WowneroWallet; -abstract class WowneroWalletBase - extends WalletBase with Store { +abstract class WowneroWalletBase extends WalletBase with Store { WowneroWalletBase( - {required WalletInfo walletInfo, required Box unspentCoinsInfo}) + {required WalletInfo walletInfo, + required Box unspentCoinsInfo}) : balance = ObservableMap.of({ CryptoCurrency.xmr: WowneroBalance( fullBalance: wownero_wallet.getFullBalance(accountIndex: 0), @@ -65,13 +67,17 @@ abstract class WowneroWalletBase transactionHistory = WowneroTransactionHistory(); walletAddresses = WowneroWalletAddresses(walletInfo, transactionHistory); - _onAccountChangeReaction = reaction((_) => walletAddresses.account, (Account? account) { + _onAccountChangeReaction = + reaction((_) => walletAddresses.account, (Account? account) { if (account == null) return; - balance = ObservableMap.of({ + balance = ObservableMap.of({ currency: WowneroBalance( - fullBalance: wownero_wallet.getFullBalance(accountIndex: account.id), - unlockedBalance: wownero_wallet.getUnlockedBalance(accountIndex: account.id)) + fullBalance: + wownero_wallet.getFullBalance(accountIndex: account.id), + unlockedBalance: + wownero_wallet.getUnlockedBalance(accountIndex: account.id)) }); _updateSubAddress(isEnabledAutoGenerateSubaddress, account: account); _askForUpdateTransactionHistory(); @@ -106,6 +112,11 @@ abstract class WowneroWalletBase @override String get seed => wownero_wallet.getSeed(); + String get seedLegacy { + wownero.Wallet_setSeedLanguage(wptr!, language: "English"); + return wownero_wallet.getSeedLegacy(); + } + @override MoneroWalletKeys get keys => MoneroWalletKeys( privateSpendKey: wownero_wallet.getSecretSpendKey(), @@ -122,11 +133,13 @@ abstract class WowneroWalletBase Future init() async { await walletAddresses.init(); - balance = ObservableMap.of({ + balance = ObservableMap.of({ currency: WowneroBalance( - fullBalance: wownero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id), - unlockedBalance: - wownero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id)) + fullBalance: wownero_wallet.getFullBalance( + accountIndex: walletAddresses.account!.id), + unlockedBalance: wownero_wallet.getUnlockedBalance( + accountIndex: walletAddresses.account!.id)) }); _setListeners(); await updateTransactions(); @@ -135,12 +148,13 @@ abstract class WowneroWalletBase wownero_wallet.setRecoveringFromSeed(isRecovery: walletInfo.isRecovery); if (wownero_wallet.getCurrentHeight() <= 1) { - wownero_wallet.setRefreshFromBlockHeight(height: walletInfo.restoreHeight); + wownero_wallet.setRefreshFromBlockHeight( + height: walletInfo.restoreHeight); } } - _autoSaveTimer = - Timer.periodic(Duration(seconds: _autoSaveInterval), (_) async => await save()); + _autoSaveTimer = Timer.periodic( + Duration(seconds: _autoSaveInterval), (_) async => await save()); } @override @@ -212,8 +226,8 @@ abstract class WowneroWalletBase final inputs = []; final outputs = _credentials.outputs; final hasMultiDestination = outputs.length > 1; - final unlockedBalance = - wownero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id); + final unlockedBalance = wownero_wallet.getUnlockedBalance( + accountIndex: walletAddresses.account!.id); var allInputsAmount = 0; PendingTransactionDescription pendingTransactionDescription; @@ -235,16 +249,20 @@ abstract class WowneroWalletBase final spendAllCoins = inputs.length == unspentCoins.length; if (hasMultiDestination) { - if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) { - throw WowneroTransactionCreationException('You do not have enough XMR to send this amount.'); + if (outputs.any( + (item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) { + throw WowneroTransactionCreationException( + 'You do not have enough XMR to send this amount.'); } - final int totalAmount = - outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)); + final int totalAmount = outputs.fold( + 0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)); - final estimatedFee = calculateEstimatedFee(_credentials.priority, totalAmount); + final estimatedFee = + calculateEstimatedFee(_credentials.priority, totalAmount); if (unlockedBalance < totalAmount) { - throw WowneroTransactionCreationException('You do not have enough XMR to send this amount.'); + throw WowneroTransactionCreationException( + 'You do not have enough XMR to send this amount.'); } if (!spendAllCoins && (allInputsAmount < totalAmount + estimatedFee)) { @@ -252,22 +270,28 @@ abstract class WowneroWalletBase } final wowneroOutputs = outputs.map((output) { - final outputAddress = output.isParsedAddress ? output.extractedAddress : output.address; + final outputAddress = + output.isParsedAddress ? output.extractedAddress : output.address; return WowneroOutput( - address: outputAddress!, amount: output.cryptoAmount!.replaceAll(',', '.')); + address: outputAddress!, + amount: output.cryptoAmount!.replaceAll(',', '.')); }).toList(); - pendingTransactionDescription = await transaction_history.createTransactionMultDest( - outputs: wowneroOutputs, - priorityRaw: _credentials.priority.serialize(), - accountIndex: walletAddresses.account!.id, - preferredInputs: inputs); + pendingTransactionDescription = + await transaction_history.createTransactionMultDest( + outputs: wowneroOutputs, + priorityRaw: _credentials.priority.serialize(), + accountIndex: walletAddresses.account!.id, + preferredInputs: inputs); } else { final output = outputs.first; - final address = output.isParsedAddress ? output.extractedAddress : output.address; - final amount = output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.'); - final formattedAmount = output.sendAll ? null : output.formattedCryptoAmount; + final address = + output.isParsedAddress ? output.extractedAddress : output.address; + final amount = + output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.'); + final formattedAmount = + output.sendAll ? null : output.formattedCryptoAmount; if ((formattedAmount != null && unlockedBalance < formattedAmount) || (formattedAmount == null && unlockedBalance <= 0)) { @@ -277,19 +301,22 @@ abstract class WowneroWalletBase 'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.'); } - final estimatedFee = calculateEstimatedFee(_credentials.priority, formattedAmount); + final estimatedFee = + calculateEstimatedFee(_credentials.priority, formattedAmount); if (!spendAllCoins && - ((formattedAmount != null && allInputsAmount < (formattedAmount + estimatedFee)) || + ((formattedAmount != null && + allInputsAmount < (formattedAmount + estimatedFee)) || formattedAmount == null)) { throw WowneroTransactionNoInputsException(inputs.length); } - pendingTransactionDescription = await transaction_history.createTransaction( - address: address!, - amount: amount, - priorityRaw: _credentials.priority.serialize(), - accountIndex: walletAddresses.account!.id, - preferredInputs: inputs); + pendingTransactionDescription = + await transaction_history.createTransaction( + address: address!, + amount: amount, + priorityRaw: _credentials.priority.serialize(), + accountIndex: walletAddresses.account!.id, + preferredInputs: inputs); } return PendingWowneroTransaction(pendingTransactionDescription); @@ -347,18 +374,17 @@ abstract class WowneroWalletBase final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.address; await Isolate.run(() { wownero.WalletManager_closeWallet( - Pointer.fromAddress(wmaddr), - Pointer.fromAddress(waddr), - true - ); + Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true); }); openedWalletsByPath.remove("$currentWalletDirPath/$name"); print("wallet closed"); } try { // -- rename the waller folder -- - final currentWalletDir = Directory(await pathForWalletDir(name: name, type: type)); - final newWalletDirPath = await pathForWalletDir(name: newWalletName, type: type); + final currentWalletDir = + Directory(await pathForWalletDir(name: name, type: type)); + final newWalletDirPath = + await pathForWalletDir(name: newWalletName, type: type); await currentWalletDir.rename(newWalletDirPath); // -- use new waller folder to rename files with old names still -- @@ -368,7 +394,8 @@ abstract class WowneroWalletBase final currentKeysFile = File('$renamedWalletPath.keys'); final currentAddressListFile = File('$renamedWalletPath.address.txt'); - final newWalletPath = await pathForWallet(name: newWalletName, type: type); + final newWalletPath = + await pathForWallet(name: newWalletName, type: type); if (currentCacheFile.existsSync()) { await currentCacheFile.rename(newWalletPath); @@ -388,7 +415,8 @@ abstract class WowneroWalletBase final currentKeysFile = File('$currentWalletPath.keys'); final currentAddressListFile = File('$currentWalletPath.address.txt'); - final newWalletPath = await pathForWallet(name: newWalletName, type: type); + final newWalletPath = + await pathForWallet(name: newWalletName, type: type); // Copies current wallet files into new wallet name's dir and files if (currentCacheFile.existsSync()) { @@ -407,7 +435,8 @@ abstract class WowneroWalletBase } @override - Future changePassword(String password) async => wownero_wallet.setPasswordSync(password); + Future changePassword(String password) async => + wownero_wallet.setPasswordSync(password); Future getNodeHeight() async => wownero_wallet.getNodeHeight(); @@ -452,7 +481,8 @@ abstract class WowneroWalletBase wownero.CoinsInfo_unlocked(coin), ); if (unspent.hash.isNotEmpty) { - unspent.isChange = transaction_history.getTransaction(unspent.hash) == 1; + unspent.isChange = + transaction_history.getTransaction(unspent.hash) == 1; } unspentCoins.add(unspent); } @@ -514,13 +544,15 @@ abstract class WowneroWalletBase Future _refreshUnspentCoinsInfo() async { try { final List keys = []; - final currentWalletUnspentCoins = unspentCoinsInfo.values.where((element) => - element.walletId.contains(id) && element.accountIndex == walletAddresses.account!.id); + final currentWalletUnspentCoins = unspentCoinsInfo.values.where( + (element) => + element.walletId.contains(id) && + element.accountIndex == walletAddresses.account!.id); if (currentWalletUnspentCoins.isNotEmpty) { currentWalletUnspentCoins.forEach((element) { - final existUnspentCoins = - unspentCoins.where((coin) => element.keyImage!.contains(coin.keyImage!)); + final existUnspentCoins = unspentCoins + .where((coin) => element.keyImage!.contains(coin.keyImage!)); if (existUnspentCoins.isEmpty) { keys.add(element.key); @@ -537,14 +569,17 @@ abstract class WowneroWalletBase } String getTransactionAddress(int accountIndex, int addressIndex) => - wownero_wallet.getAddress(accountIndex: accountIndex, addressIndex: addressIndex); + wownero_wallet.getAddress( + accountIndex: accountIndex, addressIndex: addressIndex); @override Future> fetchTransactions() async { transaction_history.refreshTransactions(); return _getAllTransactionsOfAccount(walletAddresses.account?.id) - .fold>({}, - (Map acc, WowneroTransactionInfo tx) { + .fold>( + {}, + (Map acc, + WowneroTransactionInfo tx) { acc[tx.id] = tx; return acc; }); @@ -571,28 +606,32 @@ abstract class WowneroWalletBase String getSubaddressLabel(int accountIndex, int addressIndex) => wownero_wallet.getSubaddressLabel(accountIndex, addressIndex); - List _getAllTransactionsOfAccount(int? accountIndex) => transaction_history - .getAllTransactions() - .map((row) => WowneroTransactionInfo( - row.hash, - row.blockheight, - row.isSpend ? TransactionDirection.outgoing : TransactionDirection.incoming, - row.timeStamp, - row.isPending, - row.amount, - row.accountIndex, - 0, - row.fee, - row.confirmations, - - )..additionalInfo = { - 'key': row.key, - 'accountIndex': row.accountIndex, - 'addressIndex': row.addressIndex - }, - ) - .where((element) => element.accountIndex == (accountIndex ?? 0)) - .toList(); + List _getAllTransactionsOfAccount( + int? accountIndex) => + transaction_history + .getAllTransactions() + .map( + (row) => WowneroTransactionInfo( + row.hash, + row.blockheight, + row.isSpend + ? TransactionDirection.outgoing + : TransactionDirection.incoming, + row.timeStamp, + row.isPending, + row.amount, + row.accountIndex, + 0, + row.fee, + row.confirmations, + )..additionalInfo = { + 'key': row.key, + 'accountIndex': row.accountIndex, + 'addressIndex': row.addressIndex + }, + ) + .where((element) => element.accountIndex == (accountIndex ?? 0)) + .toList(); void _setListeners() { _listener?.stop(); @@ -630,7 +669,8 @@ abstract class WowneroWalletBase } int _getHeightDistance(DateTime date) { - final distance = DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch; + final distance = + DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch; final daysTmp = (distance / 86400).round(); final days = daysTmp < 1 ? 1 : daysTmp; @@ -658,22 +698,27 @@ abstract class WowneroWalletBase balance[currency]!.unlockedBalance != unlockedBalance || balance[currency]!.frozenBalance != frozenBalance) { balance[currency] = WowneroBalance( - fullBalance: fullBalance, unlockedBalance: unlockedBalance, frozenBalance: frozenBalance); + fullBalance: fullBalance, + unlockedBalance: unlockedBalance, + frozenBalance: frozenBalance); } } - Future _askForUpdateTransactionHistory() async => await updateTransactions(); + Future _askForUpdateTransactionHistory() async => + await updateTransactions(); - int _getFullBalance() => wownero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id); + int _getFullBalance() => + wownero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id); - int _getUnlockedBalance() => - wownero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id); + int _getUnlockedBalance() => wownero_wallet.getUnlockedBalance( + accountIndex: walletAddresses.account!.id); int _getFrozenBalance() { var frozenBalance = 0; for (var coin in unspentCoinsInfo.values.where((element) => - element.walletId == id && element.accountIndex == walletAddresses.account!.id)) { + element.walletId == id && + element.accountIndex == walletAddresses.account!.id)) { if (coin.isFrozen) frozenBalance += coin.value; } diff --git a/lib/view_model/wallet_keys_view_model.dart b/lib/view_model/wallet_keys_view_model.dart index 828f863c5..187df293c 100644 --- a/lib/view_model/wallet_keys_view_model.dart +++ b/lib/view_model/wallet_keys_view_model.dart @@ -9,6 +9,8 @@ import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_type.dart'; +import 'package:cw_monero/monero_wallet.dart'; +import 'package:cw_wownero/wownero_wallet.dart'; import 'package:mobx/mobx.dart'; import 'package:polyseed/polyseed.dart'; @@ -37,10 +39,12 @@ abstract class WalletKeysViewModelBase with Store { _appStore.wallet!.type == WalletType.wownero) { final accountTransactions = _getWalletTransactions(_appStore.wallet!); if (accountTransactions.isNotEmpty) { - final incomingAccountTransactions = - accountTransactions.where((tx) => tx.direction == TransactionDirection.incoming); + final incomingAccountTransactions = accountTransactions + .where((tx) => tx.direction == TransactionDirection.incoming); if (incomingAccountTransactions.isNotEmpty) { - incomingAccountTransactions.toList().sort((a, b) => a.date.compareTo(b.date)); + incomingAccountTransactions + .toList() + .sort((a, b) => a.date.compareTo(b.date)); _restoreHeightByTransactions = _getRestoreHeightByTransactions( _appStore.wallet!.type, incomingAccountTransactions.first.date); } @@ -66,29 +70,36 @@ abstract class WalletKeysViewModelBase with Store { items.addAll([ if (keys['publicSpendKey'] != null) - StandartListItem(title: S.current.spend_key_public, value: keys['publicSpendKey']!), + StandartListItem( + title: S.current.spend_key_public, + value: keys['publicSpendKey']!), if (keys['privateSpendKey'] != null) - StandartListItem(title: S.current.spend_key_private, value: keys['privateSpendKey']!), + StandartListItem( + title: S.current.spend_key_private, + value: keys['privateSpendKey']!), if (keys['publicViewKey'] != null) - StandartListItem(title: S.current.view_key_public, value: keys['publicViewKey']!), + StandartListItem( + title: S.current.view_key_public, value: keys['publicViewKey']!), if (keys['privateViewKey'] != null) - StandartListItem(title: S.current.view_key_private, value: keys['privateViewKey']!), - StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!), + StandartListItem( + title: S.current.view_key_private, + value: keys['privateViewKey']!), + StandartListItem( + title: S.current.wallet_seed, value: _appStore.wallet!.seed!), ]); - if (_appStore.wallet?.seed != null && Polyseed.isValidSeed(_appStore.wallet!.seed!)) { - final lang = PolyseedLang.getByPhrase(_appStore.wallet!.seed!); - final legacyLang = _getLegacySeedLang(lang); - final legacySeed = - Polyseed.decode(_appStore.wallet!.seed!, lang, PolyseedCoin.POLYSEED_MONERO) - .toLegacySeed(legacyLang); - items.add(StandartListItem(title: S.current.wallet_seed_legacy, value: legacySeed)); + if (_appStore.wallet?.seed != null && + Polyseed.isValidSeed(_appStore.wallet!.seed!)) { + items.add(StandartListItem( + title: S.current.wallet_seed_legacy, + value: (_appStore.wallet as MoneroWalletBase).seedLegacy)); } final restoreHeight = monero!.getRestoreHeight(_appStore.wallet!); if (restoreHeight != null) { items.add(StandartListItem( - title: S.current.wallet_recovery_height, value: restoreHeight.toString())); + title: S.current.wallet_recovery_height, + value: restoreHeight.toString())); } } @@ -97,14 +108,22 @@ abstract class WalletKeysViewModelBase with Store { items.addAll([ if (keys['publicSpendKey'] != null) - StandartListItem(title: S.current.spend_key_public, value: keys['publicSpendKey']!), + StandartListItem( + title: S.current.spend_key_public, + value: keys['publicSpendKey']!), if (keys['privateSpendKey'] != null) - StandartListItem(title: S.current.spend_key_private, value: keys['privateSpendKey']!), + StandartListItem( + title: S.current.spend_key_private, + value: keys['privateSpendKey']!), if (keys['publicViewKey'] != null) - StandartListItem(title: S.current.view_key_public, value: keys['publicViewKey']!), + StandartListItem( + title: S.current.view_key_public, value: keys['publicViewKey']!), if (keys['privateViewKey'] != null) - StandartListItem(title: S.current.view_key_private, value: keys['privateViewKey']!), - StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!), + StandartListItem( + title: S.current.view_key_private, + value: keys['privateViewKey']!), + StandartListItem( + title: S.current.wallet_seed, value: _appStore.wallet!.seed!), ]); } @@ -113,23 +132,29 @@ abstract class WalletKeysViewModelBase with Store { items.addAll([ if (keys['publicSpendKey'] != null) - StandartListItem(title: S.current.spend_key_public, value: keys['publicSpendKey']!), + StandartListItem( + title: S.current.spend_key_public, + value: keys['publicSpendKey']!), if (keys['privateSpendKey'] != null) - StandartListItem(title: S.current.spend_key_private, value: keys['privateSpendKey']!), + StandartListItem( + title: S.current.spend_key_private, + value: keys['privateSpendKey']!), if (keys['publicViewKey'] != null) - StandartListItem(title: S.current.view_key_public, value: keys['publicViewKey']!), + StandartListItem( + title: S.current.view_key_public, value: keys['publicViewKey']!), if (keys['privateViewKey'] != null) - StandartListItem(title: S.current.view_key_private, value: keys['privateViewKey']!), - StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!), + StandartListItem( + title: S.current.view_key_private, + value: keys['privateViewKey']!), + StandartListItem( + title: S.current.wallet_seed, value: _appStore.wallet!.seed!), ]); - if (_appStore.wallet?.seed != null && Polyseed.isValidSeed(_appStore.wallet!.seed!)) { - final lang = PolyseedLang.getByPhrase(_appStore.wallet!.seed!); - final legacyLang = _getLegacySeedLang(lang); - final legacySeed = - Polyseed.decode(_appStore.wallet!.seed!, lang, PolyseedCoin.POLYSEED_WOWNERO) - .toLegacySeed(legacyLang); - items.add(StandartListItem(title: S.current.wallet_seed_legacy, value: legacySeed)); + if (_appStore.wallet?.seed != null && + Polyseed.isValidSeed(_appStore.wallet!.seed!)) { + items.add(StandartListItem( + title: S.current.wallet_seed_legacy, + value: (_appStore.wallet as WowneroWalletBase).seedLegacy)); } } @@ -145,7 +170,8 @@ abstract class WalletKeysViewModelBase with Store { // StandartListItem(title: S.current.private_key, value: keys['privateKey']!), // if (keys['publicKey'] != null) // StandartListItem(title: S.current.public_key, value: keys['publicKey']!), - StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!), + StandartListItem( + title: S.current.wallet_seed, value: _appStore.wallet!.seed!), ]); } @@ -154,24 +180,32 @@ abstract class WalletKeysViewModelBase with Store { _appStore.wallet!.type == WalletType.tron) { items.addAll([ if (_appStore.wallet!.privateKey != null) - StandartListItem(title: S.current.private_key, value: _appStore.wallet!.privateKey!), + StandartListItem( + title: S.current.private_key, + value: _appStore.wallet!.privateKey!), if (_appStore.wallet!.seed != null) - StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!), + StandartListItem( + title: S.current.wallet_seed, value: _appStore.wallet!.seed!), ]); } - bool nanoBased = - _appStore.wallet!.type == WalletType.nano || _appStore.wallet!.type == WalletType.banano; + bool nanoBased = _appStore.wallet!.type == WalletType.nano || + _appStore.wallet!.type == WalletType.banano; if (nanoBased) { // we always have the hex version of the seed and private key: items.addAll([ if (_appStore.wallet!.seed != null) - StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!), + StandartListItem( + title: S.current.wallet_seed, value: _appStore.wallet!.seed!), if (_appStore.wallet!.hexSeed != null) - StandartListItem(title: S.current.seed_hex_form, value: _appStore.wallet!.hexSeed!), + StandartListItem( + title: S.current.seed_hex_form, + value: _appStore.wallet!.hexSeed!), if (_appStore.wallet!.privateKey != null) - StandartListItem(title: S.current.private_key, value: _appStore.wallet!.privateKey!), + StandartListItem( + title: S.current.private_key, + value: _appStore.wallet!.privateKey!), ]); } } @@ -216,7 +250,8 @@ abstract class WalletKeysViewModelBase with Store { case WalletType.wownero: return 'wownero-wallet'; default: - throw Exception('Unexpected wallet type: ${_appStore.wallet!.toString()}'); + throw Exception( + 'Unexpected wallet type: ${_appStore.wallet!.toString()}'); } } @@ -237,7 +272,8 @@ abstract class WalletKeysViewModelBase with Store { if (_appStore.wallet!.seed != null) 'seed': _appStore.wallet!.seed!, if (_appStore.wallet!.seed == null && _appStore.wallet!.hexSeed != null) 'hexSeed': _appStore.wallet!.hexSeed!, - if (_appStore.wallet!.seed == null && _appStore.wallet!.privateKey != null) + if (_appStore.wallet!.seed == null && + _appStore.wallet!.privateKey != null) 'private_key': _appStore.wallet!.privateKey!, if (restoreHeightResult != null) ...{'height': restoreHeightResult} }; @@ -254,7 +290,11 @@ abstract class WalletKeysViewModelBase with Store { } else if (wallet.type == WalletType.haven) { return haven!.getTransactionHistory(wallet).transactions.values.toList(); } else if (wallet.type == WalletType.wownero) { - return wownero!.getTransactionHistory(wallet).transactions.values.toList(); + return wownero! + .getTransactionHistory(wallet) + .transactions + .values + .toList(); } return []; } @@ -270,7 +310,8 @@ abstract class WalletKeysViewModelBase with Store { return 0; } - String getRoundedRestoreHeight(int height) => ((height / 1000).floor() * 1000).toString(); + String getRoundedRestoreHeight(int height) => + ((height / 1000).floor() * 1000).toString(); LegacySeedLang _getLegacySeedLang(PolyseedLang lang) { switch (lang.nameEnglish) { diff --git a/scripts/prepare_moneroc.sh b/scripts/prepare_moneroc.sh index 80bbd0f96..297666968 100755 --- a/scripts/prepare_moneroc.sh +++ b/scripts/prepare_moneroc.sh @@ -8,7 +8,7 @@ if [[ ! -d "monero_c" ]]; then git clone https://github.com/mrcyjanek/monero_c --branch rewrite-wip cd monero_c - git checkout 21e05d6ef33aa3fc6e2550da3b2200d3bcedfc35 + git checkout 57f19be240a40e15e6f58d4b3945ea75bdc61279 git reset --hard git submodule update --init --force --recursive ./apply_patches.sh monero