monero refactor with some fixes applied to wownero as well

This commit is contained in:
julian 2024-01-08 13:40:07 -06:00
parent 4232ef8d8a
commit f43ae8788d
11 changed files with 2469 additions and 1303 deletions

View file

@ -500,7 +500,13 @@ class _NewWalletRecoveryPhraseWarningViewState
Constants.defaultSeedPhraseLengthFor(
coin: info.coin,
);
if (wordCount > 0) {
if (coin == Coin.monero ||
coin == Coin.wownero) {
// currently a special case due to the
// xmr/wow libraries handling their
// own mnemonic generation
} else if (wordCount > 0) {
if (ref
.read(pNewWalletOptions.state)
.state !=

View file

@ -8,6 +8,8 @@
*
*/
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
@ -79,8 +81,8 @@ class CoinWalletsTable extends ConsumerWidget {
ref.read(pWallets).getWallet(walletIds[i]);
if (wallet.info.coin == Coin.monero ||
wallet.info.coin == Coin.wownero) {
// TODO: this can cause ui lag
await wallet.init();
// TODO: this can cause ui lag if awaited
unawaited(wallet.init());
}
await Navigator.of(context).pushNamed(

View file

@ -16,7 +16,6 @@ import 'package:stackwallet/models/node_model.dart';
import 'package:stackwallet/models/paymint/fee_object_model.dart';
import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart';
import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart';
import 'package:stackwallet/services/coins/monero/monero_wallet.dart';
import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart';
import 'package:stackwallet/services/coins/particl/particl_wallet.dart';
import 'package:stackwallet/services/coins/stellar/stellar_wallet.dart';
@ -120,13 +119,7 @@ abstract class CoinServiceAPI {
);
case Coin.monero:
return MoneroWallet(
walletId: walletId,
walletName: walletName,
coin: coin,
secureStorage: secureStorageInterface,
// tracker: tracker,
);
throw UnimplementedError("moved");
case Coin.particl:
return ParticlWallet(

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,47 @@
import 'package:cw_monero/api/wallet.dart' as monero_wallet;
import 'package:stackwallet/models/node_model.dart';
import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
import 'package:stackwallet/wallets/crypto_currency/intermediate/cryptonote_currency.dart';
class Monero extends CryptonoteCurrency {
Monero(super.network) {
switch (network) {
case CryptoCurrencyNetwork.main:
coin = Coin.monero;
default:
throw Exception("Unsupported network: $network");
}
}
@override
int get minConfirms => 10;
@override
bool validateAddress(String address) {
return monero_wallet.validateAddress(address);
}
@override
NodeModel get defaultNode {
switch (network) {
case CryptoCurrencyNetwork.main:
return NodeModel(
host: "https://monero.stackwallet.com",
port: 18081,
name: DefaultNodes.defaultName,
id: DefaultNodes.buildId(Coin.monero),
useSSL: true,
enabled: true,
coinName: Coin.monero.name,
isFailover: true,
isDown: false,
trusted: true,
);
default:
throw UnimplementedError();
}
}
}

View file

@ -286,7 +286,7 @@ class WalletInfo implements IsarId {
}
}
/// copies this with a new name and updates the db
/// Can be dangerous. Don't use unless you know the consequences
Future<void> setMnemonicVerified({
required Isar isar,
}) async {
@ -294,7 +294,6 @@ class WalletInfo implements IsarId {
await isar.walletInfoMeta.where().walletIdEqualTo(walletId).findFirst();
if (meta == null) {
await isar.writeTxn(() async {
await isar.walletInfoMeta.deleteByWalletId(walletId);
await isar.walletInfoMeta.put(
WalletInfoMeta(
walletId: walletId,
@ -304,6 +303,7 @@ class WalletInfo implements IsarId {
});
} else if (meta.isMnemonicVerified == false) {
await isar.writeTxn(() async {
await isar.walletInfoMeta.deleteByWalletId(walletId);
await isar.walletInfoMeta.put(
WalletInfoMeta(
walletId: walletId,
@ -319,6 +319,26 @@ class WalletInfo implements IsarId {
}
}
/// copies this with a new name and updates the db
Future<void> updateRestoreHeight({
required int newRestoreHeight,
required Isar isar,
}) async {
// don't allow empty names
if (newRestoreHeight < 0) {
throw Exception("Negative restore height not allowed!");
}
// only update if there were changes to the name
if (restoreHeight != newRestoreHeight) {
_restoreHeight = newRestoreHeight;
await isar.writeTxn(() async {
await isar.walletInfo.deleteByWalletId(walletId);
await isar.walletInfo.put(this);
});
}
}
//============================================================================
WalletInfo({

View file

@ -1,3 +1,4 @@
import 'package:cw_monero/pending_monero_transaction.dart';
import 'package:cw_wownero/pending_wownero_transaction.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/v2/transaction_v2.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
@ -45,6 +46,9 @@ class TxData {
// wownero specific
final PendingWowneroTransaction? pendingWowneroTransaction;
// monero specific
final PendingMoneroTransaction? pendingMoneroTransaction;
// firo lelantus specific
final int? jMintValue;
final List<int>? spendCoinIndexes;
@ -91,6 +95,7 @@ class TxData {
this.chainId,
this.feeInWei,
this.pendingWowneroTransaction,
this.pendingMoneroTransaction,
this.jMintValue,
this.spendCoinIndexes,
this.height,
@ -165,6 +170,7 @@ class TxData {
BigInt? chainId,
BigInt? feeInWei,
PendingWowneroTransaction? pendingWowneroTransaction,
PendingMoneroTransaction? pendingMoneroTransaction,
int? jMintValue,
List<int>? spendCoinIndexes,
int? height,
@ -207,6 +213,8 @@ class TxData {
feeInWei: feeInWei ?? this.feeInWei,
pendingWowneroTransaction:
pendingWowneroTransaction ?? this.pendingWowneroTransaction,
pendingMoneroTransaction:
pendingMoneroTransaction ?? this.pendingMoneroTransaction,
jMintValue: jMintValue ?? this.jMintValue,
spendCoinIndexes: spendCoinIndexes ?? this.spendCoinIndexes,
height: height ?? this.height,
@ -244,6 +252,7 @@ class TxData {
'chainId: $chainId, '
'feeInWei: $feeInWei, '
'pendingWowneroTransaction: $pendingWowneroTransaction, '
'pendingMoneroTransaction: $pendingMoneroTransaction, '
'jMintValue: $jMintValue, '
'spendCoinIndexes: $spendCoinIndexes, '
'height: $height, '

File diff suppressed because it is too large Load diff

View file

@ -42,6 +42,7 @@ import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart';
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
import 'package:stackwallet/wallets/models/tx_data.dart';
import 'package:stackwallet/wallets/wallet/intermediate/cryptonote_wallet.dart';
import 'package:stackwallet/wallets/wallet/wallet.dart';
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/multi_address_interface.dart';
import 'package:tuple/tuple.dart';
@ -312,6 +313,7 @@ class WowneroWallet extends CryptonoteWallet with MultiAddressInterface {
}
cwWalletBase = (await cwWalletService!.openWallet(walletId, password))
as WowneroWalletBase;
unawaited(_start());
} else {
WalletInfo walletInfo;
WalletCredentials credentials;
@ -358,11 +360,21 @@ class WowneroWallet extends CryptonoteWallet with MultiAddressInterface {
// 2))); // subtract a couple days to ensure we have a buffer for SWB
final bufferedCreateHeight = getSeedHeightSync(wallet!.seed.trim());
// TODO: info.updateRestoreHeight
await DB.instance.put<dynamic>(
boxName: walletId,
key: "restoreHeight",
value: bufferedCreateHeight);
await info.updateRestoreHeight(
newRestoreHeight: bufferedCreateHeight,
isar: mainDB.isar,
);
// special case for xmr/wow. Normally mnemonic + passphrase is saved
// before wallet.init() is called
await secureStorageInterface.write(
key: Wallet.mnemonicKey(walletId: walletId),
value: wallet.seed.trim(),
);
await secureStorageInterface.write(
key: Wallet.mnemonicPassphraseKey(walletId: walletId),
value: "",
);
walletInfo.restoreHeight = bufferedCreateHeight;
@ -372,6 +384,7 @@ class WowneroWallet extends CryptonoteWallet with MultiAddressInterface {
cwWalletBase?.close();
cwWalletBase = wallet as WowneroWalletBase;
unawaited(_start());
} catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
cwWalletBase?.close();
@ -379,7 +392,7 @@ class WowneroWallet extends CryptonoteWallet with MultiAddressInterface {
await updateNode();
await cwWalletBase?.startSync();
cwWalletBase?.close();
// cwWalletBase?.close();
}
return super.init();
@ -723,6 +736,31 @@ class WowneroWallet extends CryptonoteWallet with MultiAddressInterface {
// ====== private ============================================================
Future<void> _start() async {
cwWalletBase?.onNewBlock = onNewBlock;
cwWalletBase?.onNewTransaction = onNewTransaction;
cwWalletBase?.syncStatusChanged = syncStatusChanged;
if (cwWalletBase != null && !(await cwWalletBase!.isConnected())) {
final node = getCurrentNode();
final host = Uri.parse(node.host).host;
await cwWalletBase?.connectToNode(
node: Node(
uri: "$host:${node.port}",
type: WalletType.monero,
trusted: node.trusted ?? false,
),
);
}
await cwWalletBase?.startSync();
unawaited(refresh());
_autoSaveTimer?.cancel();
_autoSaveTimer = Timer.periodic(
const Duration(seconds: 193),
(_) async => await cwWalletBase?.save(),
);
}
void onNewBlock({required int height, required int blocksLeft}) {
_currentKnownChainHeight = height;
updateChainHeight();
@ -742,7 +780,7 @@ class WowneroWallet extends CryptonoteWallet with MultiAddressInterface {
void syncStatusChanged() async {
final syncStatus = cwWalletBase?.syncStatus;
if (syncStatus != null) {
if (syncStatus.progress() == 1) {
if (syncStatus.progress() == 1 && refreshMutex.isLocked) {
refreshMutex.release();
}

View file

@ -30,11 +30,13 @@ import 'package:stackwallet/wallets/wallet/impl/ecash_wallet.dart';
import 'package:stackwallet/wallets/wallet/impl/epiccash_wallet.dart';
import 'package:stackwallet/wallets/wallet/impl/firo_wallet.dart';
import 'package:stackwallet/wallets/wallet/impl/litecoin_wallet.dart';
import 'package:stackwallet/wallets/wallet/impl/monero_wallet.dart';
import 'package:stackwallet/wallets/wallet/impl/namecoin_wallet.dart';
import 'package:stackwallet/wallets/wallet/impl/nano_wallet.dart';
import 'package:stackwallet/wallets/wallet/impl/particl_wallet.dart';
import 'package:stackwallet/wallets/wallet/impl/tezos_wallet.dart';
import 'package:stackwallet/wallets/wallet/impl/wownero_wallet.dart';
import 'package:stackwallet/wallets/wallet/intermediate/cryptonote_wallet.dart';
import 'package:stackwallet/wallets/wallet/private_key_based_wallet.dart';
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart';
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/lelantus_interface.dart';
@ -139,14 +141,19 @@ abstract class Wallet<T extends CryptoCurrency> {
);
if (wallet is MnemonicInterface) {
await secureStorageInterface.write(
key: mnemonicKey(walletId: walletInfo.walletId),
value: mnemonic!,
);
await secureStorageInterface.write(
key: mnemonicPassphraseKey(walletId: walletInfo.walletId),
value: mnemonicPassphrase!,
);
if (wallet is CryptonoteWallet) {
// currently a special case due to the xmr/wow libraries handling their
// own mnemonic generation
} else {
await secureStorageInterface.write(
key: mnemonicKey(walletId: walletInfo.walletId),
value: mnemonic!,
);
await secureStorageInterface.write(
key: mnemonicPassphraseKey(walletId: walletInfo.walletId),
value: mnemonicPassphrase!,
);
}
}
if (wallet is PrivateKeyBasedWallet) {
@ -281,6 +288,9 @@ abstract class Wallet<T extends CryptoCurrency> {
case Coin.litecoinTestNet:
return LitecoinWallet(CryptoCurrencyNetwork.test);
case Coin.monero:
return MoneroWallet(CryptoCurrencyNetwork.main);
case Coin.namecoin:
return NamecoinWallet(CryptoCurrencyNetwork.main);

View file

@ -97,7 +97,8 @@ class SimpleWalletCard extends ConsumerWidget {
final wallet = ref.read(pWallets).getWallet(walletId);
if (wallet.info.coin == Coin.monero || wallet.info.coin == Coin.wownero) {
await wallet.init();
// TODO: this can cause ui lag if awaited
unawaited(wallet.init());
}
if (context.mounted) {
if (popPrevious) nav.pop();