mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 12:29:51 +00:00
fix(cw_monero): prevent monero wallet from breaking during rename (#2214)
* fix(cw_monero): prevent monero wallet from breaking during rename * update to cleaned up monero.dart * fix: transaction screen not refreshing in monero * fix: wallets not opening until app restart after rename. * fix(cw_decred): wallet renaming throwing * fix: transaction not being shown after sending until 1st confirmation * fix(cw_monero): loop safeguard * fix: don't await wallet.fetchTransactions
This commit is contained in:
parent
dd8413bae2
commit
a2294c4a06
25 changed files with 577 additions and 714 deletions
|
@ -1,6 +1,7 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:cw_core/exceptions.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
|
@ -602,7 +603,25 @@ abstract class DecredWalletBase
|
|||
throw "wallet already exists at $newDirPath";
|
||||
}
|
||||
|
||||
await Directory(currentDirPath).rename(newDirPath);
|
||||
final sourceDir = Directory(currentDirPath);
|
||||
final targetDir = Directory(newDirPath);
|
||||
|
||||
if (!targetDir.existsSync()) {
|
||||
await targetDir.create(recursive: true);
|
||||
}
|
||||
|
||||
await for (final entity in sourceDir.list(recursive: true)) {
|
||||
final relativePath = entity.path.substring(sourceDir.path.length+1);
|
||||
final targetPath = p.join(targetDir.path, relativePath);
|
||||
|
||||
if (entity is File) {
|
||||
await entity.rename(targetPath);
|
||||
} else if (entity is Directory) {
|
||||
await Directory(targetPath).create(recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
await sourceDir.delete(recursive: true);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -118,6 +118,10 @@ class DecredWalletService extends WalletService<
|
|||
currentWalletInfo.derivationInfo?.derivationPath == pubkeyRestorePathTestnet
|
||||
? testnet
|
||||
: mainnet;
|
||||
if (libwallet == null) {
|
||||
libwallet = await Libwallet.spawn();
|
||||
libwallet!.initLibdcrwallet("", "err");
|
||||
}
|
||||
final currentWallet = DecredWallet(
|
||||
currentWalletInfo, password, this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
|
||||
|
||||
|
|
|
@ -2,31 +2,31 @@ import 'dart:async';
|
|||
|
||||
import 'package:cw_monero/api/wallet.dart';
|
||||
import 'package:cw_monero/monero_account_list.dart';
|
||||
import 'package:monero/monero.dart' as monero;
|
||||
import 'package:monero/src/wallet2.dart';
|
||||
import 'package:monero/src/monero.dart';
|
||||
|
||||
monero.wallet? wptr = null;
|
||||
bool get isViewOnly => int.tryParse(monero.Wallet_secretSpendKey(wptr!)) == 0;
|
||||
Wallet2Wallet? currentWallet = null;
|
||||
bool get isViewOnly => int.tryParse(currentWallet!.secretSpendKey()) == 0;
|
||||
|
||||
int _wlptrForW = 0;
|
||||
monero.WalletListener? _wlptr = null;
|
||||
Wallet2WalletListener? _wlptr = null;
|
||||
|
||||
monero.WalletListener? getWlptr() {
|
||||
if (wptr == null) return null;
|
||||
if (wptr!.address == _wlptrForW) return _wlptr!;
|
||||
_wlptrForW = wptr!.address;
|
||||
_wlptr = monero.MONERO_cw_getWalletListener(wptr!);
|
||||
Wallet2WalletListener? getWlptr() {
|
||||
if (currentWallet == null) return null;
|
||||
_wlptrForW = currentWallet!.ffiAddress();
|
||||
_wlptr = currentWallet!.getWalletListener();
|
||||
return _wlptr!;
|
||||
}
|
||||
|
||||
monero.SubaddressAccount? subaddressAccount;
|
||||
Wallet2SubaddressAccount? subaddressAccount;
|
||||
|
||||
bool isUpdating = false;
|
||||
|
||||
void refreshAccounts() {
|
||||
try {
|
||||
isUpdating = true;
|
||||
subaddressAccount = monero.Wallet_subaddressAccount(wptr!);
|
||||
monero.SubaddressAccount_refresh(subaddressAccount!);
|
||||
subaddressAccount = currentWallet!.subaddressAccount();
|
||||
subaddressAccount!.refresh();
|
||||
isUpdating = false;
|
||||
} catch (e) {
|
||||
isUpdating = false;
|
||||
|
@ -34,45 +34,28 @@ void refreshAccounts() {
|
|||
}
|
||||
}
|
||||
|
||||
List<monero.SubaddressAccountRow> getAllAccount() {
|
||||
List<Wallet2SubaddressAccountRow> getAllAccount() {
|
||||
// final size = monero.Wallet_numSubaddressAccounts(wptr!);
|
||||
refreshAccounts();
|
||||
int size = monero.SubaddressAccount_getAll_size(subaddressAccount!);
|
||||
int size = subaddressAccount!.getAll_size();
|
||||
if (size == 0) {
|
||||
monero.Wallet_addSubaddressAccount(wptr!);
|
||||
monero.Wallet_status(wptr!);
|
||||
currentWallet!.addSubaddressAccount();
|
||||
currentWallet!.status();
|
||||
return [];
|
||||
}
|
||||
return List.generate(size, (index) {
|
||||
return monero.SubaddressAccount_getAll_byIndex(subaddressAccount!, index: index);
|
||||
return subaddressAccount!.getAll_byIndex(index);
|
||||
});
|
||||
}
|
||||
|
||||
void addAccountSync({required String label}) {
|
||||
monero.Wallet_addSubaddressAccount(wptr!, label: label);
|
||||
void addAccount({required String label}) {
|
||||
currentWallet!.addSubaddressAccount(label: label);
|
||||
unawaited(store());
|
||||
}
|
||||
|
||||
void setLabelForAccountSync({required int accountIndex, required String label}) {
|
||||
monero.SubaddressAccount_setLabel(subaddressAccount!, accountIndex: accountIndex, label: label);
|
||||
MoneroAccountListBase.cachedAccounts[wptr!.address] = [];
|
||||
void setLabelForAccount({required int accountIndex, required String label}) {
|
||||
subaddressAccount!.setLabel(accountIndex: accountIndex, label: label);
|
||||
MoneroAccountListBase.cachedAccounts[currentWallet!.ffiAddress()] = [];
|
||||
refreshAccounts();
|
||||
}
|
||||
|
||||
void _addAccount(String label) => addAccountSync(label: label);
|
||||
|
||||
void _setLabelForAccount(Map<String, dynamic> args) {
|
||||
final label = args['label'] as String;
|
||||
final accountIndex = args['accountIndex'] as int;
|
||||
|
||||
setLabelForAccountSync(label: label, accountIndex: accountIndex);
|
||||
}
|
||||
|
||||
Future<void> addAccount({required String label}) async {
|
||||
_addAccount(label);
|
||||
unawaited(store());
|
||||
}
|
||||
|
||||
Future<void> setLabelForAccount({required int accountIndex, required String label}) async {
|
||||
_setLabelForAccount({'accountIndex': accountIndex, 'label': label});
|
||||
unawaited(store());
|
||||
}
|
|
@ -3,17 +3,18 @@ import 'dart:isolate';
|
|||
|
||||
import 'package:cw_monero/api/account_list.dart';
|
||||
import 'package:monero/monero.dart' as monero;
|
||||
import 'package:monero/src/wallet2.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
|
||||
monero.Coins? coins = null;
|
||||
Wallet2Coins? coins = null;
|
||||
final coinsMutex = Mutex();
|
||||
|
||||
Future<void> refreshCoins(int accountIndex) async {
|
||||
if (coinsMutex.isLocked) {
|
||||
return;
|
||||
}
|
||||
coins = monero.Wallet_coins(wptr!);
|
||||
final coinsPtr = coins!.address;
|
||||
coins = currentWallet!.coins();
|
||||
final coinsPtr = coins!.ffiAddress();
|
||||
await coinsMutex.acquire();
|
||||
await Isolate.run(() => monero.Coins_refresh(Pointer.fromAddress(coinsPtr)));
|
||||
coinsMutex.release();
|
||||
|
@ -21,14 +22,14 @@ Future<void> refreshCoins(int accountIndex) async {
|
|||
|
||||
Future<int> countOfCoins() async {
|
||||
await coinsMutex.acquire();
|
||||
final count = monero.Coins_count(coins!);
|
||||
final count = coins!.count();
|
||||
coinsMutex.release();
|
||||
return count;
|
||||
}
|
||||
|
||||
Future<monero.CoinsInfo> getCoin(int index) async {
|
||||
Future<Wallet2CoinsInfo> getCoin(int index) async {
|
||||
await coinsMutex.acquire();
|
||||
final coin = monero.Coins_coin(coins!, index);
|
||||
final coin = coins!.coin(index);
|
||||
coinsMutex.release();
|
||||
return coin;
|
||||
}
|
||||
|
@ -37,7 +38,7 @@ Future<int?> getCoinByKeyImage(String keyImage) async {
|
|||
final count = await countOfCoins();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final coin = await getCoin(i);
|
||||
final coinAddress = monero.CoinsInfo_keyImage(coin);
|
||||
final coinAddress = coin.keyImage;
|
||||
if (keyImage == coinAddress) {
|
||||
return i;
|
||||
}
|
||||
|
@ -47,14 +48,14 @@ Future<int?> getCoinByKeyImage(String keyImage) async {
|
|||
|
||||
Future<void> freezeCoin(int index) async {
|
||||
await coinsMutex.acquire();
|
||||
final coinsPtr = coins!.address;
|
||||
final coinsPtr = coins!.ffiAddress();
|
||||
await Isolate.run(() => monero.Coins_setFrozen(Pointer.fromAddress(coinsPtr), index: index));
|
||||
coinsMutex.release();
|
||||
}
|
||||
|
||||
Future<void> thawCoin(int index) async {
|
||||
await coinsMutex.acquire();
|
||||
final coinsPtr = coins!.address;
|
||||
final coinsPtr = coins!.ffiAddress();
|
||||
await Isolate.run(() => monero.Coins_thaw(Pointer.fromAddress(coinsPtr), index: index));
|
||||
coinsMutex.release();
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
import 'package:cw_monero/api/account_list.dart';
|
||||
import 'package:cw_monero/api/transaction_history.dart';
|
||||
import 'package:cw_monero/api/wallet.dart';
|
||||
import 'package:monero/monero.dart' as monero;
|
||||
import 'package:monero/monero.dart';
|
||||
import 'package:monero/src/monero.dart';
|
||||
|
||||
bool isUpdating = false;
|
||||
|
||||
|
@ -16,7 +17,7 @@ class SubaddressInfoMetadata {
|
|||
SubaddressInfoMetadata? subaddress = null;
|
||||
|
||||
String getRawLabel({required int accountIndex, required int addressIndex}) {
|
||||
return monero.Wallet_getSubaddressLabel(wptr!, accountIndex: accountIndex, addressIndex: addressIndex);
|
||||
return currentWallet!.getSubaddressLabel(accountIndex: accountIndex, addressIndex: addressIndex);
|
||||
}
|
||||
|
||||
void refreshSubaddresses({required int accountIndex}) {
|
||||
|
@ -46,7 +47,7 @@ class Subaddress {
|
|||
final int received;
|
||||
final int txCount;
|
||||
String get label {
|
||||
final localLabel = monero.Wallet_getSubaddressLabel(wptr!, accountIndex: accountIndex, addressIndex: addressIndex);
|
||||
final localLabel = currentWallet!.getSubaddressLabel(accountIndex: accountIndex, addressIndex: addressIndex);
|
||||
if (localLabel.startsWith("#$addressIndex")) return localLabel; // don't duplicate the ID if it was user-providen
|
||||
return "#$addressIndex ${localLabel}".trim();
|
||||
}
|
||||
|
@ -66,26 +67,26 @@ int lastTxCount = 0;
|
|||
List<TinyTransactionDetails> ttDetails = [];
|
||||
|
||||
List<Subaddress> getAllSubaddresses() {
|
||||
txhistory = monero.Wallet_history(wptr!);
|
||||
final txCount = monero.TransactionHistory_count(txhistory!);
|
||||
if (lastTxCount != txCount && lastWptr != wptr!.address) {
|
||||
txhistory = currentWallet!.history();
|
||||
final txCount = txhistory!.count();
|
||||
if (lastTxCount != txCount && lastWptr != currentWallet!.ffiAddress()) {
|
||||
final List<TinyTransactionDetails> newttDetails = [];
|
||||
lastTxCount = txCount;
|
||||
lastWptr = wptr!.address;
|
||||
lastWptr = currentWallet!.ffiAddress();
|
||||
for (var i = 0; i < txCount; i++) {
|
||||
final tx = monero.TransactionHistory_transaction(txhistory!, index: i);
|
||||
if (monero.TransactionInfo_direction(tx) == monero.TransactionInfo_Direction.Out) continue;
|
||||
final subaddrs = monero.TransactionInfo_subaddrIndex(tx).split(",");
|
||||
final account = monero.TransactionInfo_subaddrAccount(tx);
|
||||
final tx = txhistory!.transaction(i);
|
||||
if (tx.direction() == TransactionInfo_Direction.Out.index) continue;
|
||||
final subaddrs = tx.subaddrIndex().split(",");
|
||||
final account = tx.subaddrAccount();
|
||||
newttDetails.add(TinyTransactionDetails(
|
||||
address: List.generate(subaddrs.length, (index) => getAddress(accountIndex: account, addressIndex: int.tryParse(subaddrs[index])??0)),
|
||||
amount: monero.TransactionInfo_amount(tx),
|
||||
amount: tx.amount(),
|
||||
));
|
||||
}
|
||||
ttDetails.clear();
|
||||
ttDetails.addAll(newttDetails);
|
||||
}
|
||||
final size = monero.Wallet_numSubaddresses(wptr!, accountIndex: subaddress!.accountIndex);
|
||||
final size = currentWallet!.numSubaddresses(accountIndex: subaddress!.accountIndex);
|
||||
final list = List.generate(size, (index) {
|
||||
final ttDetailsLocal = ttDetails.where((element) {
|
||||
final address = getAddress(
|
||||
|
@ -119,46 +120,17 @@ List<Subaddress> getAllSubaddresses() {
|
|||
}
|
||||
|
||||
int numSubaddresses(int subaccountIndex) {
|
||||
return monero.Wallet_numSubaddresses(wptr!, accountIndex: subaccountIndex);
|
||||
}
|
||||
|
||||
void addSubaddressSync({required int accountIndex, required String label}) {
|
||||
monero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex, label: label);
|
||||
refreshSubaddresses(accountIndex: accountIndex);
|
||||
}
|
||||
|
||||
void setLabelForSubaddressSync(
|
||||
{required int accountIndex, required int addressIndex, required String label}) {
|
||||
monero.Wallet_setSubaddressLabel(wptr!, accountIndex: accountIndex, addressIndex: addressIndex, label: label);
|
||||
}
|
||||
|
||||
void _addSubaddress(Map<String, dynamic> args) {
|
||||
final label = args['label'] as String;
|
||||
final accountIndex = args['accountIndex'] as int;
|
||||
|
||||
addSubaddressSync(accountIndex: accountIndex, label: label);
|
||||
}
|
||||
|
||||
void _setLabelForSubaddress(Map<String, dynamic> args) {
|
||||
final label = args['label'] as String;
|
||||
final accountIndex = args['accountIndex'] as int;
|
||||
final addressIndex = args['addressIndex'] as int;
|
||||
|
||||
setLabelForSubaddressSync(
|
||||
accountIndex: accountIndex, addressIndex: addressIndex, label: label);
|
||||
return currentWallet!.numSubaddresses(accountIndex: subaccountIndex);
|
||||
}
|
||||
|
||||
Future<void> addSubaddress({required int accountIndex, required String label}) async {
|
||||
_addSubaddress({'accountIndex': accountIndex, 'label': label});
|
||||
currentWallet!.addSubaddress(accountIndex: accountIndex, label: label);
|
||||
refreshSubaddresses(accountIndex: accountIndex);
|
||||
await store();
|
||||
}
|
||||
|
||||
Future<void> setLabelForSubaddress(
|
||||
{required int accountIndex, required int addressIndex, required String label}) async {
|
||||
_setLabelForSubaddress({
|
||||
'accountIndex': accountIndex,
|
||||
'addressIndex': addressIndex,
|
||||
'label': label
|
||||
});
|
||||
currentWallet!.setSubaddressLabel(accountIndex: accountIndex, addressIndex: addressIndex, label: label);
|
||||
await store();
|
||||
}
|
|
@ -9,36 +9,38 @@ import 'package:cw_monero/api/structs/pending_transaction.dart';
|
|||
import 'package:cw_monero/api/wallet.dart';
|
||||
import 'package:cw_monero/exceptions/monero_transaction_creation_exception.dart';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:monero/src/monero.dart';
|
||||
import 'package:monero/monero.dart' as monero;
|
||||
import 'package:monero/src/wallet2.dart';
|
||||
import 'package:monero/src/generated_bindings_monero.g.dart' as monero_gen;
|
||||
import 'package:mutex/mutex.dart';
|
||||
|
||||
|
||||
Map<int, Map<String, String>> txKeys = {};
|
||||
String getTxKey(String txId) {
|
||||
txKeys[wptr!.address] ??= {};
|
||||
if (txKeys[wptr!.address]![txId] != null) {
|
||||
return txKeys[wptr!.address]![txId]!;
|
||||
txKeys[currentWallet!.ffiAddress()] ??= {};
|
||||
if (txKeys[currentWallet!.ffiAddress()]![txId] != null) {
|
||||
return txKeys[currentWallet!.ffiAddress()]![txId]!;
|
||||
}
|
||||
final txKey = monero.Wallet_getTxKey(wptr!, txid: txId);
|
||||
final status = monero.Wallet_status(wptr!);
|
||||
final txKey = currentWallet!.getTxKey(txid: txId);
|
||||
final status = currentWallet!.status();
|
||||
if (status != 0) {
|
||||
monero.Wallet_errorString(wptr!);
|
||||
txKeys[wptr!.address]![txId] = "";
|
||||
currentWallet!.errorString();
|
||||
txKeys[currentWallet!.ffiAddress()]![txId] = "";
|
||||
return "";
|
||||
}
|
||||
txKeys[wptr!.address]![txId] = txKey;
|
||||
txKeys[currentWallet!.ffiAddress()]![txId] = txKey;
|
||||
return txKey;
|
||||
}
|
||||
|
||||
final txHistoryMutex = Mutex();
|
||||
monero.TransactionHistory? txhistory;
|
||||
Wallet2TransactionHistory? txhistory;
|
||||
bool isRefreshingTx = false;
|
||||
Future<void> refreshTransactions() async {
|
||||
if (isRefreshingTx == true) return;
|
||||
isRefreshingTx = true;
|
||||
txhistory ??= monero.Wallet_history(wptr!);
|
||||
final ptr = txhistory!.address;
|
||||
txhistory ??= currentWallet!.history();
|
||||
final ptr = txhistory!.ffiAddress();
|
||||
await txHistoryMutex.acquire();
|
||||
await Isolate.run(() {
|
||||
monero.TransactionHistory_refresh(Pointer.fromAddress(ptr));
|
||||
|
@ -48,14 +50,14 @@ Future<void> refreshTransactions() async {
|
|||
isRefreshingTx = false;
|
||||
}
|
||||
|
||||
int countOfTransactions() => monero.TransactionHistory_count(txhistory!);
|
||||
int countOfTransactions() => txhistory!.count();
|
||||
|
||||
Future<List<Transaction>> getAllTransactions() async {
|
||||
List<Transaction> dummyTxs = [];
|
||||
|
||||
await txHistoryMutex.acquire();
|
||||
txhistory ??= monero.Wallet_history(wptr!);
|
||||
final startAddress = txhistory!.address * wptr!.address;
|
||||
txhistory ??= currentWallet!.history();
|
||||
final startAddress = txhistory!.ffiAddress() * currentWallet!.ffiAddress();
|
||||
int size = countOfTransactions();
|
||||
final list = <Transaction>[];
|
||||
for (int index = 0; index < size; index++) {
|
||||
|
@ -63,21 +65,21 @@ Future<List<Transaction>> getAllTransactions() async {
|
|||
// Give main thread a chance to do other things.
|
||||
await Future.delayed(Duration.zero);
|
||||
}
|
||||
if (txhistory!.address * wptr!.address != startAddress) {
|
||||
if (txhistory!.ffiAddress() * currentWallet!.ffiAddress() != startAddress) {
|
||||
printV("Loop broken because txhistory!.address * wptr!.address != startAddress");
|
||||
break;
|
||||
}
|
||||
final txInfo = monero.TransactionHistory_transaction(txhistory!, index: index);
|
||||
final txHash = monero.TransactionInfo_hash(txInfo);
|
||||
txCache[wptr!.address] ??= {};
|
||||
txCache[wptr!.address]![txHash] = Transaction(txInfo: txInfo);
|
||||
list.add(txCache[wptr!.address]![txHash]!);
|
||||
final txInfo = txhistory!.transaction(index);
|
||||
final txHash = txInfo.hash();
|
||||
txCache[currentWallet!.ffiAddress()] ??= {};
|
||||
txCache[currentWallet!.ffiAddress()]![txHash] = Transaction(txInfo: txInfo);
|
||||
list.add(txCache[currentWallet!.ffiAddress()]![txHash]!);
|
||||
}
|
||||
txHistoryMutex.release();
|
||||
final accts = monero.Wallet_numSubaddressAccounts(wptr!);
|
||||
final accts = currentWallet!.numSubaddressAccounts();
|
||||
for (var i = 0; i < accts; i++) {
|
||||
final fullBalance = monero.Wallet_balance(wptr!, accountIndex: i);
|
||||
final availBalance = monero.Wallet_unlockedBalance(wptr!, accountIndex: i);
|
||||
final fullBalance = currentWallet!.balance(accountIndex: i);
|
||||
final availBalance = currentWallet!.unlockedBalance(accountIndex: i);
|
||||
if (fullBalance > availBalance) {
|
||||
if (list.where((element) => element.accountIndex == i && element.isConfirmed == false).isEmpty) {
|
||||
dummyTxs.add(
|
||||
|
@ -95,7 +97,7 @@ Future<List<Transaction>> getAllTransactions() async {
|
|||
isSpend: false,
|
||||
hash: "pending",
|
||||
key: "",
|
||||
txInfo: Pointer.fromAddress(0),
|
||||
txInfo: DummyTransaction(),
|
||||
)..timeStamp = DateTime.now()
|
||||
);
|
||||
}
|
||||
|
@ -105,16 +107,21 @@ Future<List<Transaction>> getAllTransactions() async {
|
|||
return list;
|
||||
}
|
||||
|
||||
class DummyTransaction implements Wallet2TransactionInfo {
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
}
|
||||
|
||||
Map<int, Map<String, Transaction>> txCache = {};
|
||||
Future<Transaction> getTransaction(String txId) async {
|
||||
if (txCache[wptr!.address] != null && txCache[wptr!.address]![txId] != null) {
|
||||
return txCache[wptr!.address]![txId]!;
|
||||
if (txCache[currentWallet!.ffiAddress()] != null && txCache[currentWallet!.ffiAddress()]![txId] != null) {
|
||||
return txCache[currentWallet!.ffiAddress()]![txId]!;
|
||||
}
|
||||
await txHistoryMutex.acquire();
|
||||
final tx = monero.TransactionHistory_transactionById(txhistory!, txid: txId);
|
||||
final tx = txhistory!.transactionById(txId);
|
||||
final txDart = Transaction(txInfo: tx);
|
||||
txCache[wptr!.address] ??= {};
|
||||
txCache[wptr!.address]![txId] = txDart;
|
||||
txCache[currentWallet!.ffiAddress()] ??= {};
|
||||
txCache[currentWallet!.ffiAddress()]![txId] = txDart;
|
||||
txHistoryMutex.release();
|
||||
return txDart;
|
||||
}
|
||||
|
@ -127,9 +134,9 @@ Future<PendingTransactionDescription> createTransactionSync(
|
|||
int accountIndex = 0,
|
||||
List<String> preferredInputs = const []}) async {
|
||||
|
||||
final amt = amount == null ? 0 : monero.Wallet_amountFromString(amount);
|
||||
final amt = amount == null ? 0 : currentWallet!.amountFromString(amount);
|
||||
|
||||
final waddr = wptr!.address;
|
||||
final waddr = currentWallet!.ffiAddress();
|
||||
|
||||
// force reconnection in case the os killed the connection?
|
||||
// fixes failed to get block height error.
|
||||
|
@ -149,7 +156,7 @@ Future<PendingTransactionDescription> createTransactionSync(
|
|||
final paymentIdAddr = paymentId_.address;
|
||||
final preferredInputsAddr = preferredInputs_.address;
|
||||
final spaddr = monero.defaultSeparator.address;
|
||||
final pendingTx = Pointer<Void>.fromAddress(await Isolate.run(() {
|
||||
final pendingTxPtr = Pointer<Void>.fromAddress(await Isolate.run(() {
|
||||
final tx = monero_gen.MoneroC(DynamicLibrary.open(monero.libPath)).MONERO_Wallet_createTransaction(
|
||||
Pointer.fromAddress(waddr),
|
||||
Pointer.fromAddress(addraddr).cast(),
|
||||
|
@ -163,15 +170,16 @@ Future<PendingTransactionDescription> createTransactionSync(
|
|||
);
|
||||
return tx.address;
|
||||
}));
|
||||
final Wallet2PendingTransaction pendingTx = MoneroPendingTransaction(pendingTxPtr);
|
||||
calloc.free(address_);
|
||||
calloc.free(paymentId_);
|
||||
calloc.free(preferredInputs_);
|
||||
final String? error = (() {
|
||||
final status = monero.PendingTransaction_status(pendingTx);
|
||||
final status = pendingTx.status();
|
||||
if (status == 0) {
|
||||
return null;
|
||||
}
|
||||
return monero.PendingTransaction_errorString(pendingTx);
|
||||
return pendingTx.errorString();
|
||||
})();
|
||||
|
||||
if (error != null) {
|
||||
|
@ -182,10 +190,10 @@ Future<PendingTransactionDescription> createTransactionSync(
|
|||
throw CreationTransactionException(message: message);
|
||||
}
|
||||
|
||||
final rAmt = monero.PendingTransaction_amount(pendingTx);
|
||||
final rFee = monero.PendingTransaction_fee(pendingTx);
|
||||
final rHash = monero.PendingTransaction_txid(pendingTx, '');
|
||||
final rHex = monero.PendingTransaction_hex(pendingTx, '');
|
||||
final rAmt = pendingTx.amount();
|
||||
final rFee = pendingTx.fee();
|
||||
final rHash = pendingTx.txid('');
|
||||
final rHex = pendingTx.hex('');
|
||||
final rTxKey = rHash;
|
||||
|
||||
return PendingTransactionDescription(
|
||||
|
@ -194,7 +202,7 @@ Future<PendingTransactionDescription> createTransactionSync(
|
|||
hash: rHash,
|
||||
hex: rHex,
|
||||
txKey: rTxKey,
|
||||
pointerAddress: pendingTx.address,
|
||||
pointerAddress: pendingTx.ffiAddress(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -206,9 +214,9 @@ Future<PendingTransactionDescription> createTransactionMultDest(
|
|||
List<String> preferredInputs = const []}) async {
|
||||
|
||||
final dstAddrs = outputs.map((e) => e.address).toList();
|
||||
final amounts = outputs.map((e) => monero.Wallet_amountFromString(e.amount)).toList();
|
||||
final amounts = outputs.map((e) => currentWallet!.amountFromString(e.amount)).toList();
|
||||
|
||||
final waddr = wptr!.address;
|
||||
final waddr = currentWallet!.ffiAddress();
|
||||
|
||||
// force reconnection in case the os killed the connection
|
||||
Isolate.run(() async {
|
||||
|
@ -227,49 +235,50 @@ Future<PendingTransactionDescription> createTransactionMultDest(
|
|||
).address;
|
||||
}));
|
||||
|
||||
if (monero.PendingTransaction_status(txptr) != 0) {
|
||||
throw CreationTransactionException(message: monero.PendingTransaction_errorString(txptr));
|
||||
final Wallet2PendingTransaction tx = MoneroPendingTransaction(txptr);
|
||||
|
||||
if (tx.status() != 0) {
|
||||
throw CreationTransactionException(message: tx.errorString());
|
||||
}
|
||||
|
||||
return PendingTransactionDescription(
|
||||
amount: monero.PendingTransaction_amount(txptr),
|
||||
fee: monero.PendingTransaction_fee(txptr),
|
||||
hash: monero.PendingTransaction_txid(txptr, ''),
|
||||
hex: monero.PendingTransaction_hex(txptr, ''),
|
||||
txKey: monero.PendingTransaction_txid(txptr, ''),
|
||||
pointerAddress: txptr.address,
|
||||
amount: tx.amount(),
|
||||
fee: tx.fee(),
|
||||
hash: tx.txid(''),
|
||||
hex: tx.hex(''),
|
||||
txKey: tx.txid(''),
|
||||
pointerAddress: tx.ffiAddress(),
|
||||
);
|
||||
}
|
||||
|
||||
String? commitTransactionFromPointerAddress({required int address, required bool useUR}) =>
|
||||
commitTransaction(transactionPointer: monero.PendingTransaction.fromAddress(address), useUR: useUR);
|
||||
commitTransaction(tx: MoneroPendingTransaction(Pointer.fromAddress(address)), useUR: useUR);
|
||||
|
||||
String? commitTransaction({required monero.PendingTransaction transactionPointer, required bool useUR}) {
|
||||
final transactionPointerAddress = transactionPointer.address;
|
||||
String? commitTransaction({required Wallet2PendingTransaction tx, required bool useUR}) {
|
||||
final txCommit = useUR
|
||||
? monero.PendingTransaction_commitUR(transactionPointer, 120)
|
||||
? tx.commitUR(120)
|
||||
: Isolate.run(() {
|
||||
monero.PendingTransaction_commit(
|
||||
Pointer.fromAddress(transactionPointerAddress),
|
||||
Pointer.fromAddress(tx.ffiAddress()),
|
||||
filename: '',
|
||||
overwrite: false,
|
||||
);
|
||||
});
|
||||
|
||||
String? error = (() {
|
||||
final status = monero.PendingTransaction_status(transactionPointer.cast());
|
||||
final status = tx.status();
|
||||
if (status == 0) {
|
||||
return null;
|
||||
}
|
||||
return monero.PendingTransaction_errorString(transactionPointer.cast());
|
||||
return tx.errorString();
|
||||
})();
|
||||
if (error == null) {
|
||||
error = (() {
|
||||
final status = monero.Wallet_status(wptr!);
|
||||
final status = currentWallet!.status();
|
||||
if (status == 0) {
|
||||
return null;
|
||||
}
|
||||
return monero.Wallet_errorString(wptr!);
|
||||
return currentWallet!.errorString();
|
||||
})();
|
||||
|
||||
}
|
||||
|
@ -283,43 +292,9 @@ String? commitTransaction({required monero.PendingTransaction transactionPointer
|
|||
}
|
||||
}
|
||||
|
||||
Future<PendingTransactionDescription> _createTransactionSync(Map args) async {
|
||||
final address = args['address'] as String;
|
||||
final paymentId = args['paymentId'] as String;
|
||||
final amount = args['amount'] as String?;
|
||||
final priorityRaw = args['priorityRaw'] as int;
|
||||
final accountIndex = args['accountIndex'] as int;
|
||||
final preferredInputs = args['preferredInputs'] as List<String>;
|
||||
|
||||
return createTransactionSync(
|
||||
address: address,
|
||||
paymentId: paymentId,
|
||||
amount: amount,
|
||||
priorityRaw: priorityRaw,
|
||||
accountIndex: accountIndex,
|
||||
preferredInputs: preferredInputs);
|
||||
}
|
||||
|
||||
Future<PendingTransactionDescription> createTransaction(
|
||||
{required String address,
|
||||
required int priorityRaw,
|
||||
String? amount,
|
||||
String paymentId = '',
|
||||
int accountIndex = 0,
|
||||
List<String> preferredInputs = const []}) async =>
|
||||
_createTransactionSync({
|
||||
'address': address,
|
||||
'paymentId': paymentId,
|
||||
'amount': amount,
|
||||
'priorityRaw': priorityRaw,
|
||||
'accountIndex': accountIndex,
|
||||
'preferredInputs': preferredInputs
|
||||
});
|
||||
|
||||
class Transaction {
|
||||
final String displayLabel;
|
||||
late final String subaddressLabel = monero.Wallet_getSubaddressLabel(
|
||||
wptr!,
|
||||
late final String subaddressLabel = currentWallet!.getSubaddressLabel(
|
||||
accountIndex: accountIndex,
|
||||
addressIndex: addressIndex,
|
||||
);
|
||||
|
@ -372,26 +347,26 @@ class Transaction {
|
|||
// final SubAddress? subAddress;
|
||||
// List<Transfer> transfers = [];
|
||||
// final int txIndex;
|
||||
final monero.TransactionInfo txInfo;
|
||||
final Wallet2TransactionInfo txInfo;
|
||||
Transaction({
|
||||
required this.txInfo,
|
||||
}) : displayLabel = monero.TransactionInfo_label(txInfo),
|
||||
hash = monero.TransactionInfo_hash(txInfo),
|
||||
}) : displayLabel = txInfo.label(),
|
||||
hash = txInfo.hash(),
|
||||
timeStamp = DateTime.fromMillisecondsSinceEpoch(
|
||||
monero.TransactionInfo_timestamp(txInfo) * 1000,
|
||||
txInfo.timestamp() * 1000,
|
||||
),
|
||||
isSpend = monero.TransactionInfo_direction(txInfo) ==
|
||||
monero.TransactionInfo_Direction.Out,
|
||||
amount = monero.TransactionInfo_amount(txInfo),
|
||||
paymentId = monero.TransactionInfo_paymentId(txInfo),
|
||||
accountIndex = monero.TransactionInfo_subaddrAccount(txInfo),
|
||||
addressIndex = int.tryParse(monero.TransactionInfo_subaddrIndex(txInfo).split(", ")[0]) ?? 0,
|
||||
addressIndexList = monero.TransactionInfo_subaddrIndex(txInfo).split(", ").map((e) => int.tryParse(e) ?? 0).toList(),
|
||||
blockheight = monero.TransactionInfo_blockHeight(txInfo),
|
||||
confirmations = monero.TransactionInfo_confirmations(txInfo),
|
||||
fee = monero.TransactionInfo_fee(txInfo),
|
||||
description = monero.TransactionInfo_description(txInfo),
|
||||
key = getTxKey(monero.TransactionInfo_hash(txInfo));
|
||||
isSpend = txInfo.direction() ==
|
||||
monero.TransactionInfo_Direction.Out.index,
|
||||
amount = txInfo.amount(),
|
||||
paymentId = txInfo.paymentId(),
|
||||
accountIndex = txInfo.subaddrAccount(),
|
||||
addressIndex = int.tryParse(txInfo.subaddrIndex().split(", ")[0]) ?? 0,
|
||||
addressIndexList = txInfo.subaddrIndex().split(", ").map((e) => int.tryParse(e) ?? 0).toList(),
|
||||
blockheight = txInfo.blockHeight(),
|
||||
confirmations = txInfo.confirmations(),
|
||||
fee = txInfo.fee(),
|
||||
description = txInfo.description(),
|
||||
key = getTxKey(txInfo.hash());
|
||||
|
||||
Transaction.dummy({
|
||||
required this.displayLabel,
|
||||
|
|
|
@ -5,8 +5,6 @@ import 'dart:isolate';
|
|||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_monero/api/account_list.dart';
|
||||
import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
|
||||
import 'package:cw_monero/api/wallet_manager.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:monero/monero.dart' as monero;
|
||||
import 'package:mutex/mutex.dart';
|
||||
import 'package:polyseed/polyseed.dart';
|
||||
|
@ -15,36 +13,37 @@ bool debugMonero = false;
|
|||
|
||||
int getSyncingHeight() {
|
||||
// final height = monero.MONERO_cw_WalletListener_height(getWlptr());
|
||||
final h2 = monero.Wallet_blockChainHeight(wptr!);
|
||||
if (currentWallet == null) return 0;
|
||||
final h2 = currentWallet!.blockChainHeight();
|
||||
// printV("height: $height / $h2");
|
||||
return h2;
|
||||
}
|
||||
|
||||
bool isNeededToRefresh() {
|
||||
final wlptr = getWlptr();
|
||||
if (wlptr == null) return false;
|
||||
final ret = monero.MONERO_cw_WalletListener_isNeedToRefresh(wlptr);
|
||||
monero.MONERO_cw_WalletListener_resetNeedToRefresh(wlptr);
|
||||
final wl = getWlptr();
|
||||
if (wl == null) return false;
|
||||
final ret = wl.isNeedToRefresh();
|
||||
wl.resetNeedToRefresh();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool isNewTransactionExist() {
|
||||
final wlptr = getWlptr();
|
||||
if (wlptr == null) return false;
|
||||
final ret = monero.MONERO_cw_WalletListener_isNewTransactionExist(wlptr);
|
||||
monero.MONERO_cw_WalletListener_resetIsNewTransactionExist(wlptr);
|
||||
final ret = wlptr.isNewTransactionExist();
|
||||
wlptr.resetIsNewTransactionExist();
|
||||
return ret;
|
||||
}
|
||||
|
||||
String getFilename() => monero.Wallet_filename(wptr!);
|
||||
String getFilename() => currentWallet!.filename();
|
||||
|
||||
String getSeed() {
|
||||
// monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
|
||||
final cakepolyseed =
|
||||
monero.Wallet_getCacheAttribute(wptr!, key: "cakewallet.seed");
|
||||
currentWallet!.getCacheAttribute(key: "cakewallet.seed");
|
||||
final cakepassphrase = getPassphrase();
|
||||
|
||||
final weirdPolyseed = monero.Wallet_getPolyseed(wptr!, passphrase: cakepassphrase);
|
||||
final weirdPolyseed = currentWallet!.getPolyseed(passphrase: cakepassphrase);
|
||||
if (weirdPolyseed != "") return weirdPolyseed;
|
||||
|
||||
if (cakepolyseed != "") {
|
||||
|
@ -63,7 +62,7 @@ String getSeed() {
|
|||
return cakepolyseed;
|
||||
}
|
||||
|
||||
final bip39 = monero.Wallet_getCacheAttribute(wptr!, key: "cakewallet.seed.bip39");
|
||||
final bip39 = currentWallet!.getCacheAttribute(key: "cakewallet.seed.bip39");
|
||||
|
||||
if(bip39.isNotEmpty) return bip39;
|
||||
|
||||
|
@ -85,29 +84,29 @@ String? getSeedLanguage(String? language) {
|
|||
String getSeedLegacy(String? language) {
|
||||
final cakepassphrase = getPassphrase();
|
||||
language = getSeedLanguage(language);
|
||||
var legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
|
||||
if (monero.Wallet_status(wptr!) != 0) {
|
||||
if (monero.Wallet_errorString(wptr!).contains("seed_language")) {
|
||||
monero.Wallet_setSeedLanguage(wptr!, language: "English");
|
||||
legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
|
||||
var legacy = currentWallet!.seed(seedOffset: cakepassphrase);
|
||||
if (currentWallet!.status() != 0) {
|
||||
if (currentWallet!.errorString().contains("seed_language")) {
|
||||
currentWallet!.setSeedLanguage(language: "English");
|
||||
legacy = currentWallet!.seed(seedOffset: cakepassphrase);
|
||||
}
|
||||
}
|
||||
|
||||
if (language != null) {
|
||||
monero.Wallet_setSeedLanguage(wptr!, language: language);
|
||||
final status = monero.Wallet_status(wptr!);
|
||||
currentWallet!.setSeedLanguage(language: language);
|
||||
final status = currentWallet!.status();
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(wptr!);
|
||||
final err = currentWallet!.errorString();
|
||||
if (legacy.isNotEmpty) {
|
||||
return "$err\n\n$legacy";
|
||||
}
|
||||
return err;
|
||||
}
|
||||
legacy = monero.Wallet_seed(wptr!, seedOffset: cakepassphrase);
|
||||
legacy = currentWallet!.seed(seedOffset: cakepassphrase);
|
||||
}
|
||||
|
||||
if (monero.Wallet_status(wptr!) != 0) {
|
||||
final err = monero.Wallet_errorString(wptr!);
|
||||
if (currentWallet!.status() != 0) {
|
||||
final err = currentWallet!.errorString();
|
||||
if (legacy.isNotEmpty) {
|
||||
return "$err\n\n$legacy";
|
||||
}
|
||||
|
@ -117,7 +116,7 @@ String getSeedLegacy(String? language) {
|
|||
}
|
||||
|
||||
String getPassphrase() {
|
||||
return monero.Wallet_getCacheAttribute(wptr!, key: "cakewallet.passphrase");
|
||||
return currentWallet!.getCacheAttribute(key: "cakewallet.passphrase");
|
||||
}
|
||||
|
||||
Map<int, Map<int, Map<int, String>>> addressCache = {};
|
||||
|
@ -125,31 +124,31 @@ Map<int, Map<int, Map<int, String>>> addressCache = {};
|
|||
String getAddress({int accountIndex = 0, int addressIndex = 0}) {
|
||||
// printV("getaddress: ${accountIndex}/${addressIndex}: ${monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)}: ${monero.Wallet_address(wptr!, accountIndex: accountIndex, addressIndex: addressIndex)}");
|
||||
// this could be a while loop, but I'm in favor of making it if to not cause freezes
|
||||
if (monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)-1 < addressIndex) {
|
||||
if (monero.Wallet_numSubaddressAccounts(wptr!) < accountIndex) {
|
||||
monero.Wallet_addSubaddressAccount(wptr!);
|
||||
if (currentWallet!.numSubaddresses(accountIndex: accountIndex)-1 < addressIndex) {
|
||||
if (currentWallet!.numSubaddressAccounts() < accountIndex) {
|
||||
currentWallet!.addSubaddressAccount();
|
||||
} else {
|
||||
monero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex);
|
||||
currentWallet!.addSubaddress(accountIndex: accountIndex);
|
||||
}
|
||||
}
|
||||
addressCache[wptr!.address] ??= {};
|
||||
addressCache[wptr!.address]![accountIndex] ??= {};
|
||||
addressCache[wptr!.address]![accountIndex]![addressIndex] ??= monero.Wallet_address(wptr!,
|
||||
addressCache[currentWallet!.ffiAddress()] ??= {};
|
||||
addressCache[currentWallet!.ffiAddress()]![accountIndex] ??= {};
|
||||
addressCache[currentWallet!.ffiAddress()]![accountIndex]![addressIndex] ??= currentWallet!.address(
|
||||
accountIndex: accountIndex, addressIndex: addressIndex);
|
||||
return addressCache[wptr!.address]![accountIndex]![addressIndex]!;
|
||||
return addressCache[currentWallet!.ffiAddress()]![accountIndex]![addressIndex]!;
|
||||
}
|
||||
|
||||
int getFullBalance({int accountIndex = 0}) =>
|
||||
monero.Wallet_balance(wptr!, accountIndex: accountIndex);
|
||||
currentWallet!.balance(accountIndex: accountIndex);
|
||||
|
||||
int getUnlockedBalance({int accountIndex = 0}) =>
|
||||
monero.Wallet_unlockedBalance(wptr!, accountIndex: accountIndex);
|
||||
currentWallet!.unlockedBalance(accountIndex: accountIndex);
|
||||
|
||||
int getCurrentHeight() => monero.Wallet_blockChainHeight(wptr!);
|
||||
int getCurrentHeight() => currentWallet!.blockChainHeight();
|
||||
|
||||
int getNodeHeightSync() => monero.Wallet_daemonBlockChainHeight(wptr!);
|
||||
int getNodeHeightSync() => currentWallet!.daemonBlockChainHeight();
|
||||
|
||||
bool isConnectedSync() => monero.Wallet_connected(wptr!) != 0;
|
||||
bool isConnectedSync() => currentWallet!.connected() != 0;
|
||||
|
||||
Future<bool> setupNodeSync(
|
||||
{required String address,
|
||||
|
@ -168,7 +167,7 @@ Future<bool> setupNodeSync(
|
|||
daemonPassword: $password ?? ''
|
||||
}
|
||||
''');
|
||||
final addr = wptr!.address;
|
||||
final addr = currentWallet!.ffiAddress();
|
||||
printV("init: start");
|
||||
await Isolate.run(() {
|
||||
monero.Wallet_init(Pointer.fromAddress(addr),
|
||||
|
@ -180,10 +179,10 @@ Future<bool> setupNodeSync(
|
|||
});
|
||||
printV("init: end");
|
||||
|
||||
final status = monero.Wallet_status(wptr!);
|
||||
final status = currentWallet!.status();
|
||||
|
||||
if (status != 0) {
|
||||
final error = monero.Wallet_errorString(wptr!);
|
||||
final error = currentWallet!.errorString();
|
||||
if (error != "no tx keys found for this txid") {
|
||||
printV("error: $error");
|
||||
throw SetupWalletException(message: error);
|
||||
|
@ -191,8 +190,8 @@ Future<bool> setupNodeSync(
|
|||
}
|
||||
|
||||
if (true) {
|
||||
monero.Wallet_init3(
|
||||
wptr!, argv0: '',
|
||||
currentWallet!.init3(
|
||||
argv0: '',
|
||||
defaultLogBaseName: 'moneroc',
|
||||
console: true,
|
||||
logPath: '',
|
||||
|
@ -203,19 +202,19 @@ Future<bool> setupNodeSync(
|
|||
}
|
||||
|
||||
void startRefreshSync() {
|
||||
monero.Wallet_refreshAsync(wptr!);
|
||||
monero.Wallet_startRefresh(wptr!);
|
||||
currentWallet!.refreshAsync();
|
||||
currentWallet!.startRefresh();
|
||||
}
|
||||
|
||||
|
||||
void setRefreshFromBlockHeight({required int height}) {
|
||||
monero.Wallet_setRefreshFromBlockHeight(wptr!,
|
||||
currentWallet!.setRefreshFromBlockHeight(
|
||||
refresh_from_block_height: height);
|
||||
}
|
||||
|
||||
void setRecoveringFromSeed({required bool isRecovery}) {
|
||||
monero.Wallet_setRecoveringFromSeed(wptr!, recoveringFromSeed: isRecovery);
|
||||
monero.Wallet_store(wptr!);
|
||||
currentWallet!.setRecoveringFromSeed(recoveringFromSeed: isRecovery);
|
||||
currentWallet!.store();
|
||||
}
|
||||
|
||||
final storeMutex = Mutex();
|
||||
|
@ -224,18 +223,18 @@ final storeMutex = Mutex();
|
|||
int lastStorePointer = 0;
|
||||
int lastStoreHeight = 0;
|
||||
void storeSync({bool force = false}) async {
|
||||
final addr = wptr!.address;
|
||||
final addr = currentWallet!.ffiAddress();
|
||||
final synchronized = await Isolate.run(() {
|
||||
return monero.Wallet_synchronized(Pointer.fromAddress(addr));
|
||||
});
|
||||
if (lastStorePointer == wptr!.address &&
|
||||
lastStoreHeight + 5000 > monero.Wallet_blockChainHeight(wptr!) &&
|
||||
if (lastStorePointer == addr &&
|
||||
lastStoreHeight + 5000 > currentWallet!.blockChainHeight() &&
|
||||
!synchronized &&
|
||||
!force) {
|
||||
return;
|
||||
}
|
||||
lastStorePointer = wptr!.address;
|
||||
lastStoreHeight = monero.Wallet_blockChainHeight(wptr!);
|
||||
lastStorePointer = currentWallet!.ffiAddress();
|
||||
lastStoreHeight = currentWallet!.blockChainHeight();
|
||||
await storeMutex.acquire();
|
||||
await Isolate.run(() {
|
||||
monero.Wallet_store(Pointer.fromAddress(addr));
|
||||
|
@ -244,25 +243,25 @@ void storeSync({bool force = false}) async {
|
|||
}
|
||||
|
||||
void setPasswordSync(String password) {
|
||||
monero.Wallet_setPassword(wptr!, password: password);
|
||||
currentWallet!.setPassword(password: password);
|
||||
|
||||
final status = monero.Wallet_status(wptr!);
|
||||
final status = currentWallet!.status();
|
||||
if (status != 0) {
|
||||
throw Exception(monero.Wallet_errorString(wptr!));
|
||||
throw Exception(currentWallet!.errorString());
|
||||
}
|
||||
}
|
||||
|
||||
void closeCurrentWallet() {
|
||||
monero.Wallet_stop(wptr!);
|
||||
currentWallet!.stop();
|
||||
}
|
||||
|
||||
String getSecretViewKey() => monero.Wallet_secretViewKey(wptr!);
|
||||
String getSecretViewKey() => currentWallet!.secretViewKey();
|
||||
|
||||
String getPublicViewKey() => monero.Wallet_publicViewKey(wptr!);
|
||||
String getPublicViewKey() => currentWallet!.publicViewKey();
|
||||
|
||||
String getSecretSpendKey() => monero.Wallet_secretSpendKey(wptr!);
|
||||
String getSecretSpendKey() => currentWallet!.secretSpendKey();
|
||||
|
||||
String getPublicSpendKey() => monero.Wallet_publicSpendKey(wptr!);
|
||||
String getPublicSpendKey() => currentWallet!.publicSpendKey();
|
||||
|
||||
class SyncListener {
|
||||
SyncListener(this.onNewBlock, this.onNewTransaction)
|
||||
|
@ -360,52 +359,32 @@ Future<bool> _setupNodeSync(Map<String, Object?> args) async {
|
|||
socksProxyAddress: socksProxyAddress);
|
||||
}
|
||||
|
||||
bool _isConnected(Object _) => isConnectedSync();
|
||||
|
||||
int _getNodeHeight(Object _) => getNodeHeightSync();
|
||||
|
||||
void startRefresh() => startRefreshSync();
|
||||
|
||||
Future<void> setupNode(
|
||||
{required String address,
|
||||
String? login,
|
||||
String? password,
|
||||
bool useSSL = false,
|
||||
String? socksProxyAddress,
|
||||
bool isLightWallet = false}) async =>
|
||||
_setupNodeSync({
|
||||
'address': address,
|
||||
'login': login,
|
||||
'password': password,
|
||||
'useSSL': useSSL,
|
||||
'isLightWallet': isLightWallet,
|
||||
'socksProxyAddress': socksProxyAddress
|
||||
});
|
||||
|
||||
Future<void> store() async => _storeSync(0);
|
||||
|
||||
Future<bool> isConnected() async => _isConnected(0);
|
||||
Future<bool> isConnected() async => isConnectedSync();
|
||||
|
||||
Future<int> getNodeHeight() async => _getNodeHeight(0);
|
||||
Future<int> getNodeHeight() async => getNodeHeightSync();
|
||||
|
||||
void rescanBlockchainAsync() => monero.Wallet_rescanBlockchainAsync(wptr!);
|
||||
void rescanBlockchainAsync() => currentWallet!.rescanBlockchainAsync();
|
||||
|
||||
String getSubaddressLabel(int accountIndex, int addressIndex) {
|
||||
return monero.Wallet_getSubaddressLabel(wptr!,
|
||||
return currentWallet!.getSubaddressLabel(
|
||||
accountIndex: accountIndex, addressIndex: addressIndex);
|
||||
}
|
||||
|
||||
Future setTrustedDaemon(bool trusted) async =>
|
||||
monero.Wallet_setTrustedDaemon(wptr!, arg: trusted);
|
||||
currentWallet!.setTrustedDaemon(arg: trusted);
|
||||
|
||||
Future<bool> trustedDaemon() async => monero.Wallet_trustedDaemon(wptr!);
|
||||
Future<bool> trustedDaemon() async => currentWallet!.trustedDaemon();
|
||||
|
||||
String signMessage(String message, {String address = ""}) {
|
||||
return monero.Wallet_signMessage(wptr!, message: message, address: address);
|
||||
return currentWallet!.signMessage(message: message, address: address);
|
||||
}
|
||||
|
||||
bool verifyMessage(String message, String address, String signature) {
|
||||
return monero.Wallet_verifySignedMessage(wptr!, message: message, address: address, signature: signature);
|
||||
return currentWallet!.verifySignedMessage(message: message, address: address, signature: signature);
|
||||
}
|
||||
|
||||
Map<String, List<int>> debugCallLength() => monero.debugCallLength;
|
||||
|
|
|
@ -12,6 +12,8 @@ import 'package:cw_monero/api/transaction_history.dart';
|
|||
import 'package:cw_monero/api/wallet.dart';
|
||||
import 'package:cw_monero/ledger.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:monero/src/monero.dart';
|
||||
import 'package:monero/src/wallet2.dart';
|
||||
import 'package:monero/monero.dart' as monero;
|
||||
|
||||
class MoneroCException implements Exception {
|
||||
|
@ -24,9 +26,10 @@ class MoneroCException implements Exception {
|
|||
}
|
||||
|
||||
void checkIfMoneroCIsFine() {
|
||||
final cppCsCpp = monero.MONERO_checksum_wallet2_api_c_cpp();
|
||||
final cppCsH = monero.MONERO_checksum_wallet2_api_c_h();
|
||||
final cppCsExp = monero.MONERO_checksum_wallet2_api_c_exp();
|
||||
final checksum = MoneroWalletChecksum();
|
||||
final cppCsCpp = checksum.checksum_wallet2_api_c_cpp();
|
||||
final cppCsH = checksum.checksum_wallet2_api_c_h();
|
||||
final cppCsExp = checksum.checksum_wallet2_api_c_exp();
|
||||
|
||||
final dartCsCpp = monero.wallet2_api_c_cpp_sha256;
|
||||
final dartCsH = monero.wallet2_api_c_h_sha256;
|
||||
|
@ -44,36 +47,35 @@ void checkIfMoneroCIsFine() {
|
|||
throw MoneroCException("monero_c and monero.dart wrapper export list mismatch.\nLogic errors can occur.\nRefusing to run in release mode.\ncpp: '$cppCsExp'\ndart: '$dartCsExp'");
|
||||
}
|
||||
}
|
||||
monero.WalletManager? _wmPtr;
|
||||
final monero.WalletManager wmPtr = Pointer.fromAddress((() {
|
||||
Wallet2WalletManager? _wmPtr;
|
||||
Wallet2WalletManager wmPtr = (() {
|
||||
try {
|
||||
// Problems with the wallet? Crashes? Lags? this will print all calls to xmr
|
||||
// codebase, so it will be easier to debug what happens. At least easier
|
||||
// than plugging gdb in. Especially on windows/android.
|
||||
monero.printStarts = false;
|
||||
if (kDebugMode && debugMonero) {
|
||||
monero.WalletManagerFactory_setLogLevel(4);
|
||||
MoneroWalletManagerFactory().setLogLevel(4);
|
||||
}
|
||||
_wmPtr ??= monero.WalletManagerFactory_getWalletManager();
|
||||
_wmPtr ??= MoneroWalletManagerFactory().getWalletManager();
|
||||
if (kDebugMode && debugMonero) {
|
||||
monero.WalletManagerFactory_setLogLevel(4);
|
||||
MoneroWalletManagerFactory().setLogLevel(4);
|
||||
}
|
||||
printV("ptr: $_wmPtr");
|
||||
} catch (e) {
|
||||
printV(e);
|
||||
rethrow;
|
||||
}
|
||||
return _wmPtr!.address;
|
||||
})());
|
||||
return _wmPtr!;
|
||||
})();
|
||||
|
||||
void createWalletPointer() {
|
||||
final newWptr = monero.WalletManager_createWallet(wmPtr,
|
||||
Wallet2Wallet createWalletPointer() {
|
||||
final newWptr = wmPtr.createWallet(
|
||||
path: "", password: "", language: "", networkType: 0);
|
||||
|
||||
wptr = newWptr;
|
||||
return newWptr;
|
||||
}
|
||||
|
||||
void createWalletSync(
|
||||
void createWallet(
|
||||
{required String path,
|
||||
required String password,
|
||||
required String language,
|
||||
|
@ -81,28 +83,25 @@ void createWalletSync(
|
|||
int nettype = 0}) {
|
||||
txhistory = null;
|
||||
language = getSeedLanguage(language)!;
|
||||
final newWptr = monero.WalletManager_createWallet(wmPtr,
|
||||
final newW = wmPtr.createWallet(
|
||||
path: path, password: password, language: language, networkType: 0);
|
||||
|
||||
int status = monero.Wallet_status(newWptr);
|
||||
int status = newW.status();
|
||||
if (status != 0) {
|
||||
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
|
||||
throw WalletCreationException(message: newW.errorString());
|
||||
}
|
||||
|
||||
setupBackgroundSync(password, newWptr);
|
||||
setupBackgroundSync(password, newW);
|
||||
|
||||
wptr = newWptr;
|
||||
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase);
|
||||
monero.Wallet_store(wptr!, path: path);
|
||||
openedWalletsByPath[path] = wptr!;
|
||||
currentWallet = newW;
|
||||
currentWallet!.setCacheAttribute(key: "cakewallet.passphrase", value: passphrase);
|
||||
currentWallet!.store(path: path);
|
||||
openedWalletsByPath[path] = currentWallet!;
|
||||
_lastOpenedWallet = path;
|
||||
|
||||
// is the line below needed?
|
||||
// setupNodeSync(address: "node.moneroworld.com:18089");
|
||||
}
|
||||
|
||||
bool isWalletExistSync({required String path}) {
|
||||
return monero.WalletManager_walletExists(wmPtr, path);
|
||||
bool isWalletExist({required String path}) {
|
||||
return wmPtr.walletExists(path);
|
||||
}
|
||||
|
||||
void restoreWalletFromSeedSync(
|
||||
|
@ -113,8 +112,7 @@ void restoreWalletFromSeedSync(
|
|||
int nettype = 0,
|
||||
int restoreHeight = 0}) {
|
||||
txhistory = null;
|
||||
final newWptr = monero.WalletManager_recoveryWallet(
|
||||
wmPtr,
|
||||
final newW = wmPtr.recoveryWallet(
|
||||
path: path,
|
||||
password: password,
|
||||
mnemonic: seed,
|
||||
|
@ -123,10 +121,10 @@ void restoreWalletFromSeedSync(
|
|||
networkType: 0,
|
||||
);
|
||||
|
||||
final status = monero.Wallet_status(newWptr);
|
||||
final status = newW.status();
|
||||
|
||||
if (status != 0) {
|
||||
final error = monero.Wallet_errorString(newWptr);
|
||||
final error = newW.errorString();
|
||||
if (error.contains('word list failed verification')) {
|
||||
throw WalletRestoreFromSeedException(
|
||||
message: "Seed verification failed, please make sure you entered the correct seed with the correct words order",
|
||||
|
@ -134,20 +132,20 @@ void restoreWalletFromSeedSync(
|
|||
}
|
||||
throw WalletRestoreFromSeedException(message: error);
|
||||
}
|
||||
wptr = newWptr;
|
||||
currentWallet = newW;
|
||||
|
||||
setRefreshFromBlockHeight(height: restoreHeight);
|
||||
setupBackgroundSync(password, newWptr);
|
||||
setupBackgroundSync(password, newW);
|
||||
|
||||
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase);
|
||||
currentWallet!.setCacheAttribute(key: "cakewallet.passphrase", value: passphrase);
|
||||
|
||||
openedWalletsByPath[path] = wptr!;
|
||||
openedWalletsByPath[path] = currentWallet!;
|
||||
|
||||
monero.Wallet_store(wptr!);
|
||||
currentWallet!.store(path: path);
|
||||
_lastOpenedWallet = path;
|
||||
}
|
||||
|
||||
void restoreWalletFromKeysSync(
|
||||
void restoreWalletFromKeys(
|
||||
{required String path,
|
||||
required String password,
|
||||
required String language,
|
||||
|
@ -157,8 +155,8 @@ void restoreWalletFromKeysSync(
|
|||
int nettype = 0,
|
||||
int restoreHeight = 0}) {
|
||||
txhistory = null;
|
||||
var newWptr = (spendKey != "")
|
||||
? monero.WalletManager_createDeterministicWalletFromSpendKey(wmPtr,
|
||||
var newW = (spendKey != "")
|
||||
? wmPtr.createDeterministicWalletFromSpendKey(
|
||||
path: path,
|
||||
password: password,
|
||||
language: language,
|
||||
|
@ -166,8 +164,7 @@ void restoreWalletFromKeysSync(
|
|||
newWallet: true,
|
||||
// TODO(mrcyjanek): safe to remove
|
||||
restoreHeight: restoreHeight)
|
||||
: monero.WalletManager_createWalletFromKeys(
|
||||
wmPtr,
|
||||
: wmPtr.createWalletFromKeys(
|
||||
path: path,
|
||||
password: password,
|
||||
restoreHeight: restoreHeight,
|
||||
|
@ -177,22 +174,21 @@ void restoreWalletFromKeysSync(
|
|||
nettype: 0,
|
||||
);
|
||||
|
||||
int status = monero.Wallet_status(newWptr);
|
||||
int status = newW.status();
|
||||
if (status != 0) {
|
||||
throw WalletRestoreFromKeysException(
|
||||
message: monero.Wallet_errorString(newWptr));
|
||||
message: newW.errorString());
|
||||
}
|
||||
|
||||
// CW-712 - Try to restore deterministic wallet first, if the view key doesn't
|
||||
// match the view key provided
|
||||
if (spendKey != "") {
|
||||
final viewKeyRestored = monero.Wallet_secretViewKey(newWptr);
|
||||
final viewKeyRestored = newW.secretViewKey();
|
||||
if (viewKey != viewKeyRestored && viewKey != "") {
|
||||
monero.WalletManager_closeWallet(wmPtr, newWptr, false);
|
||||
wmPtr.closeWallet(newW, false);
|
||||
File(path).deleteSync();
|
||||
File(path + ".keys").deleteSync();
|
||||
newWptr = monero.WalletManager_createWalletFromKeys(
|
||||
wmPtr,
|
||||
newW = wmPtr.createWalletFromKeys(
|
||||
path: path,
|
||||
password: password,
|
||||
restoreHeight: restoreHeight,
|
||||
|
@ -201,19 +197,19 @@ void restoreWalletFromKeysSync(
|
|||
spendKeyString: spendKey,
|
||||
nettype: 0,
|
||||
);
|
||||
int status = monero.Wallet_status(newWptr);
|
||||
int status = newW.status();
|
||||
if (status != 0) {
|
||||
throw WalletRestoreFromKeysException(
|
||||
message: monero.Wallet_errorString(newWptr));
|
||||
message: newW.errorString());
|
||||
}
|
||||
|
||||
setupBackgroundSync(password, newWptr);
|
||||
setupBackgroundSync(password, newW);
|
||||
}
|
||||
}
|
||||
|
||||
wptr = newWptr;
|
||||
currentWallet = newW;
|
||||
|
||||
openedWalletsByPath[path] = wptr!;
|
||||
openedWalletsByPath[path] = currentWallet!;
|
||||
_lastOpenedWallet = path;
|
||||
}
|
||||
|
||||
|
@ -228,8 +224,7 @@ void restoreWalletFromPolyseedWithOffset(
|
|||
int nettype = 0}) {
|
||||
|
||||
txhistory = null;
|
||||
final newWptr = monero.WalletManager_createWalletFromPolyseed(
|
||||
wmPtr,
|
||||
final newW = wmPtr.createWalletFromPolyseed(
|
||||
path: path,
|
||||
password: password,
|
||||
networkType: nettype,
|
||||
|
@ -240,24 +235,24 @@ void restoreWalletFromPolyseedWithOffset(
|
|||
kdfRounds: 1,
|
||||
);
|
||||
|
||||
int status = monero.Wallet_status(newWptr);
|
||||
int status = newW.status();
|
||||
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(newWptr);
|
||||
final err = newW.errorString();
|
||||
printV("err: $err");
|
||||
throw WalletRestoreFromKeysException(message: err);
|
||||
}
|
||||
|
||||
wptr = newWptr;
|
||||
currentWallet = newW;
|
||||
|
||||
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
|
||||
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: seedOffset);
|
||||
monero.Wallet_store(wptr!);
|
||||
currentWallet!.setCacheAttribute(key: "cakewallet.seed", value: seed);
|
||||
currentWallet!.setCacheAttribute(key: "cakewallet.passphrase", value: seedOffset);
|
||||
currentWallet!.store(path: path);
|
||||
|
||||
setupBackgroundSync(password, newWptr);
|
||||
setupBackgroundSync(password, currentWallet!);
|
||||
storeSync();
|
||||
|
||||
openedWalletsByPath[path] = wptr!;
|
||||
openedWalletsByPath[path] = currentWallet!;
|
||||
}
|
||||
|
||||
|
||||
|
@ -282,8 +277,7 @@ void restoreWalletFromSpendKeySync(
|
|||
// );
|
||||
|
||||
txhistory = null;
|
||||
final newWptr = monero.WalletManager_createDeterministicWalletFromSpendKey(
|
||||
wmPtr,
|
||||
final newW = wmPtr.createDeterministicWalletFromSpendKey(
|
||||
path: path,
|
||||
password: password,
|
||||
language: language,
|
||||
|
@ -292,23 +286,23 @@ void restoreWalletFromSpendKeySync(
|
|||
restoreHeight: restoreHeight,
|
||||
);
|
||||
|
||||
int status = monero.Wallet_status(newWptr);
|
||||
int status = newW.status();
|
||||
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(newWptr);
|
||||
final err = newW.errorString();
|
||||
printV("err: $err");
|
||||
throw WalletRestoreFromKeysException(message: err);
|
||||
}
|
||||
|
||||
wptr = newWptr;
|
||||
currentWallet = newW;
|
||||
|
||||
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
|
||||
currentWallet!.setCacheAttribute(key: "cakewallet.seed", value: seed);
|
||||
|
||||
storeSync();
|
||||
|
||||
setupBackgroundSync(password, newWptr);
|
||||
setupBackgroundSync(password, currentWallet!);
|
||||
|
||||
openedWalletsByPath[path] = wptr!;
|
||||
openedWalletsByPath[path] = currentWallet!;
|
||||
_lastOpenedWallet = path;
|
||||
}
|
||||
|
||||
|
@ -321,41 +315,42 @@ Future<void> restoreWalletFromHardwareWallet(
|
|||
int nettype = 0,
|
||||
int restoreHeight = 0}) async {
|
||||
txhistory = null;
|
||||
|
||||
final wmPtr = MoneroWalletManagerFactory().getWalletManager().ffiAddress();
|
||||
final newWptrAddr = await Isolate.run(() {
|
||||
return monero.WalletManager_createWalletFromDevice(wmPtr,
|
||||
return monero.WalletManager_createWalletFromDevice(Pointer.fromAddress(wmPtr),
|
||||
path: path,
|
||||
password: password,
|
||||
restoreHeight: restoreHeight,
|
||||
deviceName: deviceName)
|
||||
.address;
|
||||
});
|
||||
final newWptr = Pointer<Void>.fromAddress(newWptrAddr);
|
||||
final newW = MoneroWallet(Pointer.fromAddress(newWptrAddr));
|
||||
|
||||
final status = monero.Wallet_status(newWptr);
|
||||
final status = newW.status();
|
||||
|
||||
if (status != 0) {
|
||||
final error = monero.Wallet_errorString(newWptr);
|
||||
final error = newW.errorString();
|
||||
throw WalletRestoreFromSeedException(message: error);
|
||||
}
|
||||
|
||||
wptr = newWptr;
|
||||
currentWallet = newW;
|
||||
currentWallet!.store(path: path);
|
||||
_lastOpenedWallet = path;
|
||||
openedWalletsByPath[path] = wptr!;
|
||||
openedWalletsByPath[path] = currentWallet!;
|
||||
}
|
||||
|
||||
Map<String, monero.wallet> openedWalletsByPath = {};
|
||||
Map<String, Wallet2Wallet> openedWalletsByPath = {};
|
||||
|
||||
Future<void> loadWallet(
|
||||
{required String path, required String password, int nettype = 0}) async {
|
||||
if (openedWalletsByPath[path] != null) {
|
||||
txhistory = null;
|
||||
wptr = openedWalletsByPath[path]!;
|
||||
currentWallet = openedWalletsByPath[path]!;
|
||||
return;
|
||||
}
|
||||
if (wptr == null || path != _lastOpenedWallet) {
|
||||
if (wptr != null) {
|
||||
final addr = wptr!.address;
|
||||
if (currentWallet == null || path != _lastOpenedWallet) {
|
||||
if (currentWallet != null) {
|
||||
final addr = currentWallet!.ffiAddress();
|
||||
Isolate.run(() {
|
||||
monero.Wallet_store(Pointer.fromAddress(addr));
|
||||
});
|
||||
|
@ -366,20 +361,25 @@ Future<void> loadWallet(
|
|||
/// 0: Software Wallet
|
||||
/// 1: Ledger
|
||||
/// 2: Trezor
|
||||
late final deviceType;
|
||||
var deviceType = 0;
|
||||
|
||||
if (Platform.isAndroid || Platform.isIOS) {
|
||||
deviceType = monero.WalletManager_queryWalletDevice(
|
||||
wmPtr,
|
||||
deviceType = wmPtr.queryWalletDevice(
|
||||
keysFileName: "$path.keys",
|
||||
password: password,
|
||||
kdfRounds: 1,
|
||||
);
|
||||
final status = monero.WalletManager_errorString(wmPtr);
|
||||
final status = wmPtr.errorString();
|
||||
if (status != "") {
|
||||
printV("loadWallet:"+status);
|
||||
// This is most likely closeWallet call leaking error. This is fine.
|
||||
if (status.contains("failed to save file")) {
|
||||
printV("loadWallet: error leaked: $status");
|
||||
deviceType = 0;
|
||||
} else {
|
||||
throw WalletOpeningException(message: status);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
deviceType = 0;
|
||||
}
|
||||
|
@ -388,107 +388,47 @@ Future<void> loadWallet(
|
|||
if (gLedger == null) {
|
||||
throw Exception("Tried to open a ledger wallet with no ledger connected");
|
||||
}
|
||||
final dummyWPtr = wptr ??
|
||||
monero.WalletManager_openWallet(wmPtr, path: '', password: '');
|
||||
final dummyWPtr = (currentWallet ??
|
||||
wmPtr.openWallet(path: '', password: ''));
|
||||
enableLedgerExchange(dummyWPtr, gLedger!);
|
||||
}
|
||||
|
||||
final addr = wmPtr.address;
|
||||
final addr = wmPtr.ffiAddress();
|
||||
final newWptrAddr = await Isolate.run(() {
|
||||
return monero.WalletManager_openWallet(Pointer.fromAddress(addr),
|
||||
path: path, password: password)
|
||||
.address;
|
||||
});
|
||||
|
||||
final newWptr = Pointer<Void>.fromAddress(newWptrAddr);
|
||||
final newW = MoneroWallet(Pointer.fromAddress(newWptrAddr));
|
||||
|
||||
int status = monero.Wallet_status(newWptr);
|
||||
int status = newW.status();
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(newWptr);
|
||||
final err = newW.errorString();
|
||||
printV("loadWallet:"+err);
|
||||
throw WalletOpeningException(message: err);
|
||||
}
|
||||
if (deviceType == 0) {
|
||||
setupBackgroundSync(password, newWptr);
|
||||
setupBackgroundSync(password, newW);
|
||||
}
|
||||
|
||||
wptr = newWptr;
|
||||
currentWallet = newW;
|
||||
_lastOpenedWallet = path;
|
||||
openedWalletsByPath[path] = wptr!;
|
||||
openedWalletsByPath[path] = currentWallet!;
|
||||
}
|
||||
}
|
||||
|
||||
void setupBackgroundSync(String password, Pointer<Void>? wptrOverride) {
|
||||
if (isViewOnlyBySpendKey(wptrOverride)) {
|
||||
void setupBackgroundSync(String password, Wallet2Wallet wallet) {
|
||||
if (isViewOnlyBySpendKey(wallet)) {
|
||||
return;
|
||||
}
|
||||
monero.Wallet_setupBackgroundSync(wptrOverride ?? wptr!, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
|
||||
if (monero.Wallet_status(wptrOverride ?? wptr!) != 0) {
|
||||
wallet.setupBackgroundSync(backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
|
||||
if (wallet.status() != 0) {
|
||||
// We simply ignore the error.
|
||||
printV("setupBackgroundSync: ${monero.Wallet_errorString(wptrOverride ?? wptr!)}");
|
||||
printV("setupBackgroundSync: ${wallet.errorString()}");
|
||||
}
|
||||
}
|
||||
|
||||
void _createWallet(Map<String, dynamic> args) {
|
||||
final path = args['path'] as String;
|
||||
final password = args['password'] as String;
|
||||
final language = args['language'] as String;
|
||||
final passphrase = args['passphrase'] as String;
|
||||
|
||||
createWalletSync(path: path, password: password, language: language, passphrase: passphrase);
|
||||
}
|
||||
|
||||
void _restoreFromSeed(Map<String, dynamic> args) {
|
||||
final path = args['path'] as String;
|
||||
final password = args['password'] as String;
|
||||
final passphrase = args['passphrase'] as String;
|
||||
final seed = args['seed'] as String;
|
||||
final restoreHeight = args['restoreHeight'] as int;
|
||||
|
||||
return restoreWalletFromSeedSync(
|
||||
path: path, password: password, passphrase: passphrase, seed: seed, restoreHeight: restoreHeight);
|
||||
}
|
||||
|
||||
void _restoreFromKeys(Map<String, dynamic> args) {
|
||||
final path = args['path'] as String;
|
||||
final password = args['password'] as String;
|
||||
final language = args['language'] as String;
|
||||
final restoreHeight = args['restoreHeight'] as int;
|
||||
final address = args['address'] as String;
|
||||
final viewKey = args['viewKey'] as String;
|
||||
final spendKey = args['spendKey'] as String;
|
||||
|
||||
restoreWalletFromKeysSync(
|
||||
path: path,
|
||||
password: password,
|
||||
language: language,
|
||||
restoreHeight: restoreHeight,
|
||||
address: address,
|
||||
viewKey: viewKey,
|
||||
spendKey: spendKey);
|
||||
}
|
||||
|
||||
void _restoreFromSpendKey(Map<String, dynamic> args) {
|
||||
final path = args['path'] as String;
|
||||
final password = args['password'] as String;
|
||||
final seed = args['seed'] as String;
|
||||
final language = args['language'] as String;
|
||||
final spendKey = args['spendKey'] as String;
|
||||
final restoreHeight = args['restoreHeight'] as int;
|
||||
|
||||
restoreWalletFromSpendKeySync(
|
||||
path: path,
|
||||
password: password,
|
||||
seed: seed,
|
||||
language: language,
|
||||
restoreHeight: restoreHeight,
|
||||
spendKey: spendKey);
|
||||
}
|
||||
|
||||
Future<void> _openWallet(Map<String, String> args) async => loadWallet(
|
||||
path: args['path'] as String, password: args['password'] as String);
|
||||
|
||||
bool _isWalletExist(String path) => isWalletExistSync(path: path);
|
||||
|
||||
Future<void> openWallet(
|
||||
{required String path,
|
||||
|
@ -496,77 +436,4 @@ Future<void> openWallet(
|
|||
int nettype = 0}) async =>
|
||||
loadWallet(path: path, password: password, nettype: nettype);
|
||||
|
||||
Future<void> openWalletAsync(Map<String, String> args) async =>
|
||||
_openWallet(args);
|
||||
|
||||
Future<void> createWallet(
|
||||
{required String path,
|
||||
required String password,
|
||||
required String language,
|
||||
required String passphrase,
|
||||
int nettype = 0}) async =>
|
||||
_createWallet({
|
||||
'path': path,
|
||||
'password': password,
|
||||
'language': language,
|
||||
'passphrase': passphrase,
|
||||
'nettype': nettype
|
||||
});
|
||||
|
||||
void restoreFromSeed(
|
||||
{required String path,
|
||||
required String password,
|
||||
required String passphrase,
|
||||
required String seed,
|
||||
int nettype = 0,
|
||||
int restoreHeight = 0}) =>
|
||||
_restoreFromSeed({
|
||||
'path': path,
|
||||
'password': password,
|
||||
'passphrase': passphrase,
|
||||
'seed': seed,
|
||||
'nettype': nettype,
|
||||
'restoreHeight': restoreHeight
|
||||
});
|
||||
|
||||
Future<void> restoreFromKeys(
|
||||
{required String path,
|
||||
required String password,
|
||||
required String language,
|
||||
required String address,
|
||||
required String viewKey,
|
||||
required String spendKey,
|
||||
int nettype = 0,
|
||||
int restoreHeight = 0}) async =>
|
||||
_restoreFromKeys({
|
||||
'path': path,
|
||||
'password': password,
|
||||
'language': language,
|
||||
'address': address,
|
||||
'viewKey': viewKey,
|
||||
'spendKey': spendKey,
|
||||
'nettype': nettype,
|
||||
'restoreHeight': restoreHeight
|
||||
});
|
||||
|
||||
Future<void> restoreFromSpendKey(
|
||||
{required String path,
|
||||
required String password,
|
||||
required String seed,
|
||||
required String language,
|
||||
required String spendKey,
|
||||
int nettype = 0,
|
||||
int restoreHeight = 0}) async =>
|
||||
_restoreFromSpendKey({
|
||||
'path': path,
|
||||
'password': password,
|
||||
'seed': seed,
|
||||
'language': language,
|
||||
'spendKey': spendKey,
|
||||
'nettype': nettype,
|
||||
'restoreHeight': restoreHeight
|
||||
});
|
||||
|
||||
bool isWalletExist({required String path}) => _isWalletExist(path);
|
||||
|
||||
bool isViewOnlyBySpendKey(Pointer<Void>? wptrOverride) => int.tryParse(monero.Wallet_secretSpendKey(wptrOverride ?? wptr!)) == 0;
|
||||
bool isViewOnlyBySpendKey(Wallet2Wallet? wallet) => int.tryParse((wallet??currentWallet!).secretSpendKey()) == 0;
|
||||
|
|
|
@ -7,26 +7,26 @@ import 'package:cw_core/utils/print_verbose.dart';
|
|||
import 'package:ffi/ffi.dart';
|
||||
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||
import 'package:ledger_flutter_plus/ledger_flutter_plus_dart.dart';
|
||||
import 'package:monero/monero.dart' as monero;
|
||||
import 'package:monero/src/wallet2.dart';
|
||||
|
||||
LedgerConnection? gLedger;
|
||||
|
||||
Timer? _ledgerExchangeTimer;
|
||||
Timer? _ledgerKeepAlive;
|
||||
|
||||
void enableLedgerExchange(monero.wallet ptr, LedgerConnection connection) {
|
||||
void enableLedgerExchange(Wallet2Wallet wallet, LedgerConnection connection) {
|
||||
_ledgerExchangeTimer?.cancel();
|
||||
_ledgerExchangeTimer = Timer.periodic(Duration(milliseconds: 1), (_) async {
|
||||
final ledgerRequestLength = monero.Wallet_getSendToDeviceLength(ptr);
|
||||
final ledgerRequest = monero.Wallet_getSendToDevice(ptr)
|
||||
final ledgerRequestLength = wallet.getSendToDeviceLength();
|
||||
final ledgerRequest = wallet.getSendToDevice()
|
||||
.cast<Uint8>()
|
||||
.asTypedList(ledgerRequestLength);
|
||||
if (ledgerRequestLength > 0) {
|
||||
_ledgerKeepAlive?.cancel();
|
||||
|
||||
final Pointer<Uint8> emptyPointer = malloc<Uint8>(0);
|
||||
monero.Wallet_setDeviceSendData(
|
||||
ptr, emptyPointer.cast<UnsignedChar>(), 0);
|
||||
wallet.setDeviceSendData(
|
||||
emptyPointer.cast<UnsignedChar>(), 0);
|
||||
malloc.free(emptyPointer);
|
||||
|
||||
_logLedgerCommand(ledgerRequest, false);
|
||||
|
@ -45,8 +45,8 @@ void enableLedgerExchange(monero.wallet ptr, LedgerConnection connection) {
|
|||
result.asTypedList(response.length)[i] = response[i];
|
||||
}
|
||||
|
||||
monero.Wallet_setDeviceReceivedData(
|
||||
ptr, result.cast<UnsignedChar>(), response.length);
|
||||
wallet.setDeviceReceivedData(
|
||||
result.cast<UnsignedChar>(), response.length);
|
||||
malloc.free(result);
|
||||
keepAlive(connection);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'package:cw_monero/api/wallet_manager.dart';
|
|||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_core/account.dart';
|
||||
import 'package:cw_monero/api/account_list.dart' as account_list;
|
||||
import 'package:monero/monero.dart' as monero;
|
||||
import 'package:monero/src/monero.dart';
|
||||
|
||||
part 'monero_account_list.g.dart';
|
||||
|
||||
|
@ -50,32 +50,32 @@ abstract class MoneroAccountListBase with Store {
|
|||
List<Account> getAll() {
|
||||
final allAccounts = account_list.getAllAccount();
|
||||
final currentCount = allAccounts.length;
|
||||
cachedAccounts[account_list.wptr!.address] ??= [];
|
||||
cachedAccounts[account_list.currentWallet!.ffiAddress()] ??= [];
|
||||
|
||||
if (cachedAccounts[account_list.wptr!.address]!.length == currentCount) {
|
||||
return cachedAccounts[account_list.wptr!.address]!;
|
||||
if (cachedAccounts[account_list.currentWallet!.ffiAddress()]!.length == currentCount) {
|
||||
return cachedAccounts[account_list.currentWallet!.ffiAddress()]!;
|
||||
}
|
||||
|
||||
cachedAccounts[account_list.wptr!.address] = allAccounts.map((accountRow) {
|
||||
final balance = monero.SubaddressAccountRow_getUnlockedBalance(accountRow);
|
||||
cachedAccounts[account_list.currentWallet!.ffiAddress()] = allAccounts.map((accountRow) {
|
||||
final balance = accountRow.getUnlockedBalance();
|
||||
|
||||
return Account(
|
||||
id: monero.SubaddressAccountRow_getRowId(accountRow),
|
||||
label: monero.SubaddressAccountRow_getLabel(accountRow),
|
||||
balance: moneroAmountToString(amount: monero.Wallet_amountFromString(balance)),
|
||||
id: accountRow.getRowId(),
|
||||
label: accountRow.getLabel(),
|
||||
balance: moneroAmountToString(amount: account_list.currentWallet!.amountFromString(balance)),
|
||||
);
|
||||
}).toList();
|
||||
|
||||
return cachedAccounts[account_list.wptr!.address]!;
|
||||
return cachedAccounts[account_list.currentWallet!.ffiAddress()]!;
|
||||
}
|
||||
|
||||
Future<void> addAccount({required String label}) async {
|
||||
await account_list.addAccount(label: label);
|
||||
void addAccount({required String label}) {
|
||||
account_list.addAccount(label: label);
|
||||
update();
|
||||
}
|
||||
|
||||
Future<void> setLabelAccount({required int accountIndex, required String label}) async {
|
||||
await account_list.setLabelForAccount(accountIndex: accountIndex, label: label);
|
||||
void setLabelAccount({required int accountIndex, required String label}) {
|
||||
account_list.setLabelForAccount(accountIndex: accountIndex, label: label);
|
||||
update();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:cw_core/unspent_transaction_output.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_monero/api/coins_info.dart';
|
||||
import 'package:monero/monero.dart' as monero;
|
||||
import 'package:monero/src/monero.dart';
|
||||
|
||||
class MoneroUnspent extends Unspent {
|
||||
static Future<MoneroUnspent> fromUnspent(String address, String hash, String keyImage, int value, bool isFrozen, bool isUnlocked) async {
|
||||
|
|
|
@ -39,6 +39,7 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:hive/hive.dart';
|
||||
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:monero/src/monero.dart' as m;
|
||||
import 'package:monero/monero.dart' as monero;
|
||||
|
||||
part 'monero_wallet.g.dart';
|
||||
|
@ -84,7 +85,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
monero_wallet.getUnlockedBalance(accountIndex: account.id))
|
||||
});
|
||||
_updateSubAddress(isEnabledAutoGenerateSubaddress, account: account);
|
||||
_askForUpdateTransactionHistory();
|
||||
unawaited(updateTransactions());
|
||||
});
|
||||
|
||||
reaction((_) => isEnabledAutoGenerateSubaddress, (bool enabled) {
|
||||
|
@ -139,7 +140,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
passphrase: monero_wallet.getPassphrase());
|
||||
|
||||
int? get restoreHeight =>
|
||||
transactionHistory.transactions.values.firstOrNull?.height ?? monero.Wallet_getRefreshFromBlockHeight(wptr!);
|
||||
transactionHistory.transactions.values.firstOrNull?.height ?? currentWallet?.getRefreshFromBlockHeight();
|
||||
|
||||
monero_wallet.SyncListener? _listener;
|
||||
ReactionDisposer? _onAccountChangeReaction;
|
||||
|
@ -169,7 +170,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
if (monero_wallet.getCurrentHeight() <= 1) {
|
||||
monero_wallet.setRefreshFromBlockHeight(
|
||||
height: walletInfo.restoreHeight);
|
||||
setupBackgroundSync(password, wptr!);
|
||||
setupBackgroundSync(password, currentWallet!);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,14 +190,23 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
final currentWalletDirPath = await pathForWalletDir(name: name, type: type);
|
||||
if (openedWalletsByPath["$currentWalletDirPath/$name"] != null) {
|
||||
printV("closing wallet");
|
||||
final wmaddr = wmPtr.address;
|
||||
final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.address;
|
||||
final wmaddr = wmPtr.ffiAddress();
|
||||
final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.ffiAddress();
|
||||
openedWalletsByPath.remove("$currentWalletDirPath/$name");
|
||||
if (Platform.isWindows) {
|
||||
await Isolate.run(() {
|
||||
monero.WalletManager_closeWallet(
|
||||
Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
|
||||
monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
|
||||
});
|
||||
openedWalletsByPath.remove("$currentWalletDirPath/$name");
|
||||
wptr = null;
|
||||
} else {
|
||||
unawaited(Isolate.run(() {
|
||||
monero.WalletManager_closeWallet(
|
||||
Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
|
||||
monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
|
||||
}));
|
||||
}
|
||||
currentWallet = null;
|
||||
printV("wallet closed");
|
||||
}
|
||||
}
|
||||
|
@ -211,7 +221,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
Future<void> connectToNode({required Node node}) async {
|
||||
try {
|
||||
syncStatus = ConnectingSyncStatus();
|
||||
await monero_wallet.setupNode(
|
||||
await monero_wallet.setupNodeSync(
|
||||
address: node.uri.toString(),
|
||||
login: node.login,
|
||||
password: node.password,
|
||||
|
@ -237,10 +247,10 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
isBackgroundSyncRunning = true;
|
||||
await save();
|
||||
|
||||
monero.Wallet_startBackgroundSync(wptr!);
|
||||
final status = monero.Wallet_status(wptr!);
|
||||
currentWallet!.startBackgroundSync();
|
||||
final status = currentWallet!.status();
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(wptr!);
|
||||
final err = currentWallet!.errorString();
|
||||
isBackgroundSyncRunning = false;
|
||||
printV("startBackgroundSync: $err");
|
||||
}
|
||||
|
@ -256,9 +266,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
Future<void> stopSync() async {
|
||||
if (isBackgroundSyncRunning) {
|
||||
printV("Stopping background sync");
|
||||
monero.Wallet_store(wptr!);
|
||||
monero.Wallet_stopBackgroundSync(wptr!, '');
|
||||
monero_wallet.store();
|
||||
currentWallet!.store();
|
||||
currentWallet!.stopBackgroundSync('');
|
||||
currentWallet!.store();
|
||||
isBackgroundSyncRunning = false;
|
||||
}
|
||||
await save();
|
||||
|
@ -269,9 +279,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
Future<void> stopBackgroundSync(String password) async {
|
||||
if (isBackgroundSyncRunning) {
|
||||
printV("Stopping background sync");
|
||||
monero.Wallet_store(wptr!);
|
||||
monero.Wallet_stopBackgroundSync(wptr!, password);
|
||||
monero.Wallet_store(wptr!);
|
||||
currentWallet!.store();
|
||||
currentWallet!.stopBackgroundSync(password);
|
||||
currentWallet!.store();
|
||||
isBackgroundSyncRunning = false;
|
||||
}
|
||||
}
|
||||
|
@ -308,44 +318,44 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
}
|
||||
|
||||
Future<bool> submitTransactionUR(String ur) async {
|
||||
final retStatus = monero.Wallet_submitTransactionUR(wptr!, ur);
|
||||
final status = monero.Wallet_status(wptr!);
|
||||
final retStatus = currentWallet!.submitTransactionUR(ur);
|
||||
final status = currentWallet!.status();
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(wptr!);
|
||||
final err = currentWallet!.errorString();
|
||||
throw MoneroTransactionCreationException("unable to broadcast signed transaction: $err");
|
||||
}
|
||||
return retStatus;
|
||||
}
|
||||
|
||||
bool importKeyImagesUR(String ur) {
|
||||
final retStatus = monero.Wallet_importKeyImagesUR(wptr!, ur);
|
||||
final status = monero.Wallet_status(wptr!);
|
||||
final retStatus = currentWallet!.importKeyImagesUR(ur);
|
||||
final status = currentWallet!.status();
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(wptr!);
|
||||
final err = currentWallet!.errorString();
|
||||
throw Exception("unable to import key images: $err");
|
||||
}
|
||||
return retStatus;
|
||||
}
|
||||
|
||||
String exportOutputsUR(bool all) {
|
||||
final str = monero.Wallet_exportOutputsUR(wptr!, all: all);
|
||||
final status = monero.Wallet_status(wptr!);
|
||||
final str = currentWallet!.exportOutputsUR(all: all);
|
||||
final status = currentWallet!.status();
|
||||
if (status != 0) {
|
||||
final err = monero.Wallet_errorString(wptr!);
|
||||
final err = currentWallet!.errorString();
|
||||
throw MoneroTransactionCreationException("unable to export UR: $err");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
bool needExportOutputs(int amount) {
|
||||
if (int.tryParse(monero.Wallet_secretSpendKey(wptr!)) != 0) {
|
||||
if (int.tryParse(currentWallet!.secretSpendKey()) != 0) {
|
||||
return false;
|
||||
}
|
||||
// viewOnlyBalance - balance that we can spend
|
||||
// TODO(mrcyjanek): remove hasUnknownKeyImages when we cleanup coin control
|
||||
return (monero.Wallet_viewOnlyBalance(wptr!,
|
||||
return (currentWallet!.viewOnlyBalance(
|
||||
accountIndex: walletAddresses.account!.id) < amount) ||
|
||||
monero.Wallet_hasUnknownKeyImages(wptr!);
|
||||
currentWallet!.hasUnknownKeyImages();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -425,12 +435,13 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
if (inputs.isEmpty) MoneroTransactionCreationException(
|
||||
'No inputs selected');
|
||||
pendingTransactionDescription =
|
||||
await transaction_history.createTransaction(
|
||||
await transaction_history.createTransactionSync(
|
||||
address: address!,
|
||||
amount: amount,
|
||||
priorityRaw: _credentials.priority.serialize(),
|
||||
accountIndex: walletAddresses.account!.id,
|
||||
preferredInputs: inputs);
|
||||
preferredInputs: inputs,
|
||||
paymentId: '');
|
||||
}
|
||||
|
||||
// final status = monero.PendingTransaction_status(pendingTransactionDescription);
|
||||
|
@ -485,14 +496,25 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
final currentWalletDirPath = await pathForWalletDir(name: name, type: type);
|
||||
if (openedWalletsByPath["$currentWalletDirPath/$name"] != null) {
|
||||
// NOTE: this is realistically only required on windows.
|
||||
// That's why we await it only on that platform - other platforms actually understand
|
||||
// the concept of a file properly...
|
||||
printV("closing wallet");
|
||||
final wmaddr = wmPtr.address;
|
||||
final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.address;
|
||||
final wmaddr = wmPtr.ffiAddress();
|
||||
final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.ffiAddress();
|
||||
openedWalletsByPath.remove("$currentWalletDirPath/$name");
|
||||
if (Platform.isWindows) {
|
||||
await Isolate.run(() {
|
||||
monero.WalletManager_closeWallet(
|
||||
Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
|
||||
monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
|
||||
});
|
||||
openedWalletsByPath.remove("$currentWalletDirPath/$name");
|
||||
} else {
|
||||
unawaited(Isolate.run(() {
|
||||
monero.WalletManager_closeWallet(
|
||||
Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
|
||||
monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
|
||||
}));
|
||||
}
|
||||
printV("wallet closed");
|
||||
}
|
||||
try {
|
||||
|
@ -501,32 +523,33 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
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 --
|
||||
final renamedWalletPath = newWalletDirPath + '/$name';
|
||||
// Create new directory if it doesn't exist
|
||||
await Directory(newWalletDirPath).create(recursive: true);
|
||||
|
||||
final currentCacheFile = File(renamedWalletPath);
|
||||
final currentKeysFile = File('$renamedWalletPath.keys');
|
||||
final currentAddressListFile = File('$renamedWalletPath.address.txt');
|
||||
final backgroundSyncFile = File('$renamedWalletPath.background');
|
||||
// -- use new waller folder to copy files with old names still --
|
||||
final currentWalletPath = currentWalletDir.path + '/$name';
|
||||
|
||||
final newWalletPath =
|
||||
await pathForWallet(name: newWalletName, type: type);
|
||||
final currentCacheFile = File(currentWalletPath);
|
||||
final currentKeysFile = File('$currentWalletPath.keys');
|
||||
final currentAddressListFile = File('$currentWalletPath.address.txt');
|
||||
final backgroundSyncFile = File('$currentWalletPath.background');
|
||||
|
||||
if (currentCacheFile.existsSync()) {
|
||||
await currentCacheFile.rename(newWalletPath);
|
||||
await currentCacheFile.copy("${newWalletDirPath}/$newWalletName");
|
||||
}
|
||||
if (currentKeysFile.existsSync()) {
|
||||
await currentKeysFile.rename('$newWalletPath.keys');
|
||||
await currentKeysFile.copy("${newWalletDirPath}/$newWalletName.keys");
|
||||
}
|
||||
if (currentAddressListFile.existsSync()) {
|
||||
await currentAddressListFile.rename('$newWalletPath.address.txt');
|
||||
await currentAddressListFile.copy("${newWalletDirPath}/$newWalletName.address.txt");
|
||||
}
|
||||
if (backgroundSyncFile.existsSync()) {
|
||||
await backgroundSyncFile.rename('$newWalletPath.background');
|
||||
await backgroundSyncFile.copy("${newWalletDirPath}/$newWalletName.background");
|
||||
}
|
||||
|
||||
await currentWalletDir.delete(recursive: true);
|
||||
|
||||
await backupWalletFiles(newWalletName);
|
||||
} catch (e) {
|
||||
final currentWalletPath = await pathForWallet(name: name, type: type);
|
||||
|
@ -572,12 +595,12 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
walletInfo.restoreHeight = height;
|
||||
walletInfo.isRecovery = true;
|
||||
monero_wallet.setRefreshFromBlockHeight(height: height);
|
||||
setupBackgroundSync(password, wptr!);
|
||||
setupBackgroundSync(password, currentWallet!);
|
||||
monero_wallet.rescanBlockchainAsync();
|
||||
await startSync();
|
||||
_askForUpdateBalance();
|
||||
walletAddresses.accountList.update();
|
||||
await _askForUpdateTransactionHistory();
|
||||
await updateTransactions();
|
||||
await save();
|
||||
await walletInfo.save();
|
||||
}
|
||||
|
@ -591,15 +614,15 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
final coinCount = await countOfCoins();
|
||||
for (var i = 0; i < coinCount; i++) {
|
||||
final coin = await getCoin(i);
|
||||
final coinSpent = monero.CoinsInfo_spent(coin);
|
||||
if (coinSpent == false && monero.CoinsInfo_subaddrAccount(coin) == walletAddresses.account!.id) {
|
||||
final coinSpent = coin.spent();
|
||||
if (coinSpent == false && coin.subaddrAccount() == walletAddresses.account!.id) {
|
||||
final unspent = await MoneroUnspent.fromUnspent(
|
||||
monero.CoinsInfo_address(coin),
|
||||
monero.CoinsInfo_hash(coin),
|
||||
monero.CoinsInfo_keyImage(coin),
|
||||
monero.CoinsInfo_amount(coin),
|
||||
monero.CoinsInfo_frozen(coin),
|
||||
monero.CoinsInfo_unlocked(coin),
|
||||
coin.address(),
|
||||
coin.hash(),
|
||||
coin.keyImage(),
|
||||
coin.amount(),
|
||||
coin.frozen(),
|
||||
coin.unlocked(),
|
||||
);
|
||||
// TODO: double-check the logic here
|
||||
if (unspent.hash.isNotEmpty) {
|
||||
|
@ -704,6 +727,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
acc[tx.id] = tx;
|
||||
return acc;
|
||||
});
|
||||
// This is needed to update the transaction history when new transaction is made.
|
||||
unawaited(updateTransactions());
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
@ -792,7 +817,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
|
||||
monero_wallet.setRecoveringFromSeed(isRecovery: true);
|
||||
monero_wallet.setRefreshFromBlockHeight(height: height);
|
||||
setupBackgroundSync(password, wptr!);
|
||||
setupBackgroundSync(password, currentWallet!);
|
||||
}
|
||||
|
||||
int _getHeightDistance(DateTime date) {
|
||||
|
@ -831,9 +856,6 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> _askForUpdateTransactionHistory() async =>
|
||||
await updateTransactions();
|
||||
|
||||
int _getUnlockedBalance() => monero_wallet.getUnlockedBalance(
|
||||
accountIndex: walletAddresses.account!.id);
|
||||
|
||||
|
@ -852,13 +874,13 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
printV("onNewBlock: $height, $blocksLeft, $ptc");
|
||||
try {
|
||||
if (walletInfo.isRecovery) {
|
||||
await _askForUpdateTransactionHistory();
|
||||
await updateTransactions();
|
||||
_askForUpdateBalance();
|
||||
walletAddresses.accountList.update();
|
||||
}
|
||||
|
||||
if (blocksLeft < 100) {
|
||||
await _askForUpdateTransactionHistory();
|
||||
await updateTransactions();
|
||||
_askForUpdateBalance();
|
||||
walletAddresses.accountList.update();
|
||||
syncStatus = SyncedSyncStatus();
|
||||
|
@ -881,7 +903,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
|
||||
void _onNewTransaction() async {
|
||||
try {
|
||||
await _askForUpdateTransactionHistory();
|
||||
await updateTransactions();
|
||||
_askForUpdateBalance();
|
||||
await Future<void>.delayed(Duration(seconds: 1));
|
||||
} catch (e) {
|
||||
|
@ -917,8 +939,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
}
|
||||
|
||||
void setLedgerConnection(LedgerConnection connection) {
|
||||
final dummyWPtr = wptr ??
|
||||
monero.WalletManager_openWallet(wmPtr, path: '', password: '');
|
||||
final dummyWPtr = createWalletPointer();
|
||||
enableLedgerExchange(dummyWPtr, connection);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:cw_core/get_height_by_date.dart';
|
||||
|
@ -20,6 +22,7 @@ import 'package:cw_monero/ledger.dart';
|
|||
import 'package:cw_monero/monero_wallet.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||
import 'package:monero/src/monero.dart' as m;
|
||||
import 'package:monero/monero.dart' as monero;
|
||||
import 'package:polyseed/polyseed.dart';
|
||||
|
||||
|
@ -139,7 +142,7 @@ class MoneroWalletService extends WalletService<
|
|||
overrideHeight: heightOverride, passphrase: credentials.passphrase);
|
||||
}
|
||||
|
||||
await monero_wallet_manager.createWallet(
|
||||
monero_wallet_manager.createWallet(
|
||||
path: path,
|
||||
password: credentials.password!,
|
||||
language: credentials.language,
|
||||
|
@ -179,7 +182,7 @@ class MoneroWalletService extends WalletService<
|
|||
if (walletFilesExist(path)) await repairOldAndroidWallet(name);
|
||||
|
||||
await monero_wallet_manager
|
||||
.openWalletAsync({'path': path, 'password': password});
|
||||
.openWallet(path: path, password: password);
|
||||
final walletInfo = walletInfoSource.values
|
||||
.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
|
||||
final wallet = MoneroWallet(
|
||||
|
@ -217,13 +220,23 @@ class MoneroWalletService extends WalletService<
|
|||
if (openedWalletsByPath["$path/$wallet"] != null) {
|
||||
// NOTE: this is realistically only required on windows.
|
||||
printV("closing wallet");
|
||||
final wmaddr = wmPtr.address;
|
||||
final waddr = openedWalletsByPath["$path/$wallet"]!.address;
|
||||
// await Isolate.run(() {
|
||||
monero.WalletManager_closeWallet(
|
||||
Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), false);
|
||||
// });
|
||||
final w = openedWalletsByPath["$path/$wallet"]!;
|
||||
final wmaddr = wmPtr.ffiAddress();
|
||||
final waddr = w.ffiAddress();
|
||||
openedWalletsByPath.remove("$path/$wallet");
|
||||
if (Platform.isWindows) {
|
||||
await Isolate.run(() {
|
||||
monero.WalletManager_closeWallet(
|
||||
Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
|
||||
monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
|
||||
});
|
||||
} else {
|
||||
unawaited(Isolate.run(() {
|
||||
monero.WalletManager_closeWallet(
|
||||
Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
|
||||
monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
|
||||
}));
|
||||
}
|
||||
printV("wallet closed");
|
||||
}
|
||||
|
||||
|
@ -263,7 +276,7 @@ class MoneroWalletService extends WalletService<
|
|||
{bool? isTestnet}) async {
|
||||
try {
|
||||
final path = await pathForWallet(name: credentials.name, type: getType());
|
||||
await monero_wallet_manager.restoreFromKeys(
|
||||
monero_wallet_manager.restoreWalletFromKeys(
|
||||
path: path,
|
||||
password: credentials.password!,
|
||||
language: credentials.language,
|
||||
|
@ -293,9 +306,13 @@ class MoneroWalletService extends WalletService<
|
|||
final password = credentials.password;
|
||||
final height = credentials.height;
|
||||
|
||||
if (wptr == null) monero_wallet_manager.createWalletPointer();
|
||||
if (currentWallet == null) {
|
||||
final tmpWptr = monero_wallet_manager.createWalletPointer();
|
||||
enableLedgerExchange(tmpWptr, credentials.ledgerConnection);
|
||||
} else {
|
||||
enableLedgerExchange(currentWallet!, credentials.ledgerConnection);
|
||||
}
|
||||
|
||||
enableLedgerExchange(wptr!, credentials.ledgerConnection);
|
||||
await monero_wallet_manager.restoreWalletFromHardwareWallet(
|
||||
path: path,
|
||||
password: password!,
|
||||
|
@ -352,7 +369,7 @@ class MoneroWalletService extends WalletService<
|
|||
try {
|
||||
final path = await pathForWallet(name: credentials.name, type: getType());
|
||||
|
||||
monero_wallet_manager.restoreFromSeed(
|
||||
monero_wallet_manager.restoreWalletFromSeedSync(
|
||||
path: path,
|
||||
password: credentials.password!,
|
||||
passphrase: credentials.passphrase,
|
||||
|
@ -393,7 +410,7 @@ class MoneroWalletService extends WalletService<
|
|||
walletInfo.isRecovery = true;
|
||||
walletInfo.restoreHeight = height;
|
||||
|
||||
monero_wallet_manager.restoreFromSeed(
|
||||
monero_wallet_manager.restoreWalletFromSeedSync(
|
||||
path: path,
|
||||
password: password,
|
||||
passphrase: '',
|
||||
|
@ -401,12 +418,12 @@ class MoneroWalletService extends WalletService<
|
|||
restoreHeight: height,
|
||||
);
|
||||
|
||||
monero.Wallet_setCacheAttribute(wptr!,
|
||||
currentWallet!.setCacheAttribute(
|
||||
key: "cakewallet.seed.bip39", value: mnemonic);
|
||||
monero.Wallet_setCacheAttribute(wptr!,
|
||||
currentWallet!.setCacheAttribute(
|
||||
key: "cakewallet.passphrase", value: passphrase ?? '');
|
||||
|
||||
monero.Wallet_store(wptr!);
|
||||
currentWallet!.store();
|
||||
|
||||
final wallet = MoneroWallet(
|
||||
walletInfo: walletInfo,
|
||||
|
@ -472,7 +489,7 @@ class MoneroWalletService extends WalletService<
|
|||
walletInfo.isRecovery = true;
|
||||
walletInfo.restoreHeight = height;
|
||||
|
||||
await monero_wallet_manager.restoreFromSpendKey(
|
||||
monero_wallet_manager.restoreWalletFromSpendKeySync(
|
||||
path: path,
|
||||
password: password,
|
||||
seed: seed,
|
||||
|
@ -481,8 +498,8 @@ class MoneroWalletService extends WalletService<
|
|||
spendKey: spendKey);
|
||||
|
||||
|
||||
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
|
||||
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase??'');
|
||||
currentWallet!.setCacheAttribute(key: "cakewallet.seed", value: seed);
|
||||
currentWallet!.setCacheAttribute(key: "cakewallet.passphrase", value: passphrase??'');
|
||||
|
||||
final wallet = MoneroWallet(
|
||||
walletInfo: walletInfo,
|
||||
|
@ -529,7 +546,7 @@ class MoneroWalletService extends WalletService<
|
|||
if (walletFilesExist(path)) await repairOldAndroidWallet(name);
|
||||
|
||||
await monero_wallet_manager
|
||||
.openWalletAsync({'path': path, 'password': password});
|
||||
.openWallet(path: path, password: password);
|
||||
final walletInfo = walletInfoSource.values
|
||||
.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
|
||||
final wallet = MoneroWallet(
|
||||
|
|
|
@ -573,8 +573,8 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
path: "impls/monero.dart"
|
||||
ref: "84e52393e395d75f449bcd81e23028889538118f"
|
||||
resolved-ref: "84e52393e395d75f449bcd81e23028889538118f"
|
||||
ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
|
||||
resolved-ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
|
||||
url: "https://github.com/mrcyjanek/monero_c"
|
||||
source: git
|
||||
version: "0.0.0"
|
||||
|
|
|
@ -27,7 +27,7 @@ dependencies:
|
|||
monero:
|
||||
git:
|
||||
url: https://github.com/mrcyjanek/monero_c
|
||||
ref: 84e52393e395d75f449bcd81e23028889538118f
|
||||
ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
|
||||
path: impls/monero.dart
|
||||
mutex: ^3.1.0
|
||||
ledger_flutter_plus: ^1.4.1
|
||||
|
|
|
@ -480,8 +480,8 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
path: "impls/monero.dart"
|
||||
ref: "84e52393e395d75f449bcd81e23028889538118f"
|
||||
resolved-ref: "84e52393e395d75f449bcd81e23028889538118f"
|
||||
ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
|
||||
resolved-ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
|
||||
url: "https://github.com/mrcyjanek/monero_c"
|
||||
source: git
|
||||
version: "0.0.0"
|
||||
|
|
|
@ -25,7 +25,7 @@ dependencies:
|
|||
monero:
|
||||
git:
|
||||
url: https://github.com/mrcyjanek/monero_c
|
||||
ref: 84e52393e395d75f449bcd81e23028889538118f # monero_c hash
|
||||
ref: b335585a7fb94b315eb52bd88f2da6d3489fa508 # monero_c hash
|
||||
path: impls/monero.dart
|
||||
mutex: ^3.1.0
|
||||
|
||||
|
|
|
@ -485,8 +485,8 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
path: "impls/monero.dart"
|
||||
ref: "84e52393e395d75f449bcd81e23028889538118f"
|
||||
resolved-ref: "84e52393e395d75f449bcd81e23028889538118f"
|
||||
ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
|
||||
resolved-ref: b335585a7fb94b315eb52bd88f2da6d3489fa508
|
||||
url: "https://github.com/mrcyjanek/monero_c"
|
||||
source: git
|
||||
version: "0.0.0"
|
||||
|
|
|
@ -26,7 +26,7 @@ dependencies:
|
|||
monero:
|
||||
git:
|
||||
url: https://github.com/mrcyjanek/monero_c
|
||||
ref: 84e52393e395d75f449bcd81e23028889538118f # monero_c hash
|
||||
ref: b335585a7fb94b315eb52bd88f2da6d3489fa508 # monero_c hash
|
||||
path: impls/monero.dart
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
@ -208,42 +208,40 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d
|
||||
connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf
|
||||
CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90
|
||||
cw_decred: 9c0e1df74745b51a1289ec5e91fb9e24b68fa14a
|
||||
cw_mweb: 22cd01dfb8ad2d39b15332006f22046aaa8352a3
|
||||
device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7
|
||||
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
|
||||
devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926
|
||||
cw_decred: a02cf30175a46971c1e2fa22c48407534541edc6
|
||||
cw_mweb: 3aea2fb35b2bd04d8b2d21b83216f3b8fb768d85
|
||||
device_display_brightness: 04374ebd653619292c1d996f00f42877ea19f17f
|
||||
device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89
|
||||
devicelocale: bd64aa714485a8afdaded0892c1e7d5b7f680cf8
|
||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||
fast_scanner: 44c00940355a51258cd6c2085734193cd23d95bc
|
||||
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
||||
fast_scanner: 2cb1ad3e69e645e9980fb4961396ce5804caa3e3
|
||||
file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
|
||||
flutter_local_authentication: 1172a4dd88f6306dadce067454e2c4caf07977bb
|
||||
flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f
|
||||
flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
|
||||
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
|
||||
fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
|
||||
in_app_review: a31b5257259646ea78e0e35fc914979b0031d011
|
||||
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
|
||||
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
|
||||
flutter_local_authentication: 989278c681612f1ee0e36019e149137f114b9d7f
|
||||
flutter_mailer: 3a8cd4f36c960fb04528d5471097270c19fec1c4
|
||||
flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418
|
||||
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
|
||||
in_app_review: 5596fe56fab799e8edb3561c03d053363ab13457
|
||||
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
|
||||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||
reown_yttrium: c0e87e5965fa60a3559564cc35cffbba22976089
|
||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
||||
ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda
|
||||
SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8
|
||||
sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
|
||||
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12
|
||||
sensitive_clipboard: 161e9abc3d56b3131309d8a321eb4690a803c16b
|
||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
||||
sp_scanner: b1bc9321690980bdb44bba7ec85d5543e716d1b5
|
||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
||||
universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
|
||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||
wakelock_plus: 76957ab028e12bfa4e66813c99e46637f367fc7e
|
||||
YttriumWrapper: 31e937fe9fbe0f1314d2ca6be9ce9b379a059966
|
||||
uni_links: ed8c961e47ed9ce42b6d91e1de8049e38a4b3152
|
||||
universal_ble: ff19787898040d721109c6324472e5dd4bc86adc
|
||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
||||
|
||||
PODFILE CHECKSUM: 5296465b1c6d14d506230356756826012f65d97a
|
||||
|
||||
|
|
|
@ -32,17 +32,18 @@ class WalletLoadingService {
|
|||
|
||||
Future<void> renameWallet(WalletType type, String name, String newName,
|
||||
{String? password}) async {
|
||||
try {
|
||||
final walletService = walletServiceFactory.call(type);
|
||||
final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
|
||||
|
||||
// Save the current wallet's password to the new wallet name's key
|
||||
await keyService.saveWalletPassword(walletName: newName, password: walletPassword);
|
||||
|
||||
await walletService.rename(name, walletPassword, newName);
|
||||
// Delete previous wallet name from keyService to keep only new wallet's name
|
||||
// otherwise keeps duplicate (old and new names)
|
||||
await keyService.deleteWalletPassword(walletName: name);
|
||||
|
||||
await walletService.rename(name, walletPassword, newName);
|
||||
|
||||
// set shared preferences flag based on previous wallet name
|
||||
if (type == WalletType.monero) {
|
||||
final oldNameKey = PreferencesKey.moneroWalletUpdateV1Key(name);
|
||||
|
@ -50,6 +51,10 @@ class WalletLoadingService {
|
|||
final newNameKey = PreferencesKey.moneroWalletUpdateV1Key(newName);
|
||||
await sharedPreferences.setBool(newNameKey, isPasswordUpdated);
|
||||
}
|
||||
} catch (error, stack) {
|
||||
await ExceptionHandler.resetLastPopupDate();
|
||||
await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
|
||||
}
|
||||
}
|
||||
|
||||
Future<WalletBase> load(WalletType type, String name, {String? password, bool isBackground = false}) async {
|
||||
|
|
|
@ -39,14 +39,14 @@ class CWMoneroAccountList extends MoneroAccountList {
|
|||
@override
|
||||
Future<void> addAccount(Object wallet, {required String label}) async {
|
||||
final moneroWallet = wallet as MoneroWallet;
|
||||
await moneroWallet.walletAddresses.accountList.addAccount(label: label);
|
||||
moneroWallet.walletAddresses.accountList.addAccount(label: label);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setLabelAccount(Object wallet,
|
||||
{required int accountIndex, required String label}) async {
|
||||
final moneroWallet = wallet as MoneroWallet;
|
||||
await moneroWallet.walletAddresses.accountList
|
||||
moneroWallet.walletAddresses.accountList
|
||||
.setLabelAccount(accountIndex: accountIndex, label: label);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -271,10 +271,19 @@ abstract class DashboardViewModelBase with Store {
|
|||
});
|
||||
|
||||
_transactionDisposer?.reaction.dispose();
|
||||
_transactionDisposer = reaction(
|
||||
(_) => appStore.wallet!.transactionHistory.transactions.length,
|
||||
_transactionDisposerCallback,
|
||||
);
|
||||
_transactionDisposer = reaction((_) {
|
||||
final length = appStore.wallet!.transactionHistory.transactions.length;
|
||||
if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
int confirmations = 1;
|
||||
if (![WalletType.solana, WalletType.tron].contains(wallet.type)) {
|
||||
try {
|
||||
confirmations = appStore.wallet!.transactionHistory.transactions.values.first.confirmations + 1;
|
||||
} catch (_) {}
|
||||
}
|
||||
return length * confirmations;
|
||||
}, _transactionDisposerCallback);
|
||||
|
||||
if (hasSilentPayments) {
|
||||
silentPaymentsScanningActive = bitcoin!.getScanningActive(wallet);
|
||||
|
@ -891,8 +900,19 @@ abstract class DashboardViewModelBase with Store {
|
|||
|
||||
_transactionDisposer?.reaction.dispose();
|
||||
|
||||
_transactionDisposer = reaction((_) => appStore.wallet!.transactionHistory.transactions.length,
|
||||
_transactionDisposerCallback);
|
||||
_transactionDisposer = reaction((_) {
|
||||
final length = appStore.wallet!.transactionHistory.transactions.length;
|
||||
if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
int confirmations = 1;
|
||||
if (![WalletType.solana, WalletType.tron].contains(wallet.type)) {
|
||||
try {
|
||||
confirmations = appStore.wallet!.transactionHistory.transactions.values.first.confirmations + 1;
|
||||
} catch (_) {}
|
||||
}
|
||||
return length * confirmations;
|
||||
}, _transactionDisposerCallback);
|
||||
}
|
||||
|
||||
@action
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/address_validator.dart';
|
||||
import 'package:cake_wallet/core/amount_validator.dart';
|
||||
|
@ -591,7 +593,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
|||
}
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
await sharedPreferences.setString(PreferencesKey.backgroundSyncLastTrigger(wallet.name), DateTime.now().add(Duration(minutes: 1)).toIso8601String());
|
||||
|
||||
unawaited(wallet.fetchTransactions());
|
||||
state = TransactionCommitted();
|
||||
} catch (e) {
|
||||
state = FailureState(translateErrorMessage(e, wallet.type, wallet.currency));
|
||||
|
|
|
@ -8,7 +8,7 @@ if [[ ! -d "monero_c/.git" ]];
|
|||
then
|
||||
git clone https://github.com/mrcyjanek/monero_c --branch master monero_c
|
||||
cd monero_c
|
||||
git checkout 84e52393e395d75f449bcd81e23028889538118f
|
||||
git checkout b335585a7fb94b315eb52bd88f2da6d3489fa508
|
||||
git reset --hard
|
||||
git submodule update --init --force --recursive
|
||||
./apply_patches.sh monero
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue