WIP migrate flutter_libmonero to cs_monero

This commit is contained in:
julian 2024-10-18 16:55:12 -06:00 committed by julian-CStack
parent 4109e7ed9f
commit 16b9254761
67 changed files with 1728 additions and 2529 deletions

22
.gitignore vendored
View file

@ -101,21 +101,7 @@ pubspec.yaml
# FVM Version Cache
.fvm/
android/app/src/main/jniLibs/arm64-v8a/libwownero_wallet2_api_c.so
android/app/src/main/jniLibs/arm64-v8a/libmonero_wallet2_api_c.so
android/app/src/main/jniLibs/armeabi-v7a/libmonero_wallet2_api_c.so
android/app/src/main/jniLibs/armeabi-v7a/libwownero_wallet2_api_c.so
android/app/src/main/jniLibs/x86_64/libmonero_wallet2_api_c.so
android/app/src/main/jniLibs/x86_64/libwownero_wallet2_api_c.so
macos/monero_wallet2_api_c.dylib
macos/wownero_wallet2_api_c.dylib
/macos/monero_libwallet2_api_c.dylib
/macos/wownero_libwallet2_api_c.dylib
/ios/monero_libwallet2_api_c.dylib
/ios/wownero_libwallet2_api_c.dylib
/android/app/src/main/jniLibs/arm64-v8a/libmonero_libwallet2_api_c.so
/android/app/src/main/jniLibs/armeabi-v7a/libmonero_libwallet2_api_c.so
/android/app/src/main/jniLibs/x86_64/libmonero_libwallet2_api_c.so
/android/app/src/main/jniLibs/arm64-v8a/libwownero_libwallet2_api_c.so
/android/app/src/main/jniLibs/armeabi-v7a/libwownero_libwallet2_api_c.so
/android/app/src/main/jniLibs/x86_64/libwownero_libwallet2_api_c.so
scripts/linux/build/libsecret/subprojects/gi-docgen/.meson-subproject-wrap-hash.txt
crypto_plugins/cs_monero/built_outputs
crypto_plugins/cs_monero/build

6
.gitmodules vendored
View file

@ -1,12 +1,12 @@
[submodule "crypto_plugins/flutter_libepiccash"]
path = crypto_plugins/flutter_libepiccash
url = https://github.com/cypherstack/flutter_libepiccash.git
[submodule "crypto_plugins/flutter_libmonero"]
path = crypto_plugins/flutter_libmonero
url = https://github.com/cypherstack/flutter_libmonero.git
[submodule "crypto_plugins/flutter_liblelantus"]
path = crypto_plugins/flutter_liblelantus
url = https://github.com/cypherstack/flutter_liblelantus.git
[submodule "crypto_plugins/frostdart"]
path = crypto_plugins/frostdart
url = https://github.com/cypherstack/frostdart
[submodule "crypto_plugins/cs_monero"]
path = crypto_plugins/cs_monero
url = https://github.com/cypherstack/cs_monero

@ -0,0 +1 @@
Subproject commit fee51e29e97ee8c1f57082b126173eeaf39a79f1

@ -1 +0,0 @@
Subproject commit 66369ef5b432e4d58e76b6cc4f91a5e24eb6b1ea

View file

@ -1 +0,0 @@
MoneroWallet

View file

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>23E224</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>MoneroWallet</string>
<key>CFBundleIdentifier</key>
<string>com.cypherstack.MoneroWallet</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>MoneroWallet</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>???</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>21E210</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>DTPlatformVersion</key>
<string>17.4</string>
<key>DTSDKBuild</key>
<string>21E210</string>
<key>DTSDKName</key>
<string>iphoneos17.4</string>
<key>DTXcode</key>
<string>1530</string>
<key>DTXcodeBuild</key>
<string>15E204a</string>
<key>MinimumOSVersion</key>
<string>16.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
</dict>
</plist>

View file

@ -1 +0,0 @@
WowneroWallet

View file

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>23E224</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>WowneroWallet</string>
<key>CFBundleIdentifier</key>
<string>com.cypherstack.WowneroWallet</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>WowneroWallet</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>???</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>21E210</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>DTPlatformVersion</key>
<string>17.4</string>
<key>DTSDKBuild</key>
<string>21E210</string>
<key>DTSDKName</key>
<string>iphoneos17.4</string>
<key>DTXcode</key>
<string>1530</string>
<key>DTXcodeBuild</key>
<string>15E204a</string>
<key>MinimumOSVersion</key>
<string>16.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
</dict>
</plist>

View file

@ -10,7 +10,7 @@
import 'dart:isolate';
import 'package:cw_core/wallet_info.dart' as xmr;
import 'package:compat/compat.dart' as lib_monero_compat;
import 'package:hive/hive.dart' show Box;
import 'package:hive/src/hive_impl.dart';
import 'package:mutex/mutex.dart';
@ -71,7 +71,7 @@ class DB {
Box<Trade>? _boxTradesV2;
Box<String>? _boxTradeNotes;
Box<String>? _boxFavoriteWallets;
Box<xmr.WalletInfo>? _walletInfoSource;
Box<lib_monero_compat.WalletInfo>? _walletInfoSource;
Box<dynamic>? _boxPrefs;
Box<TradeWalletLookup>? _boxTradeLookup;
Box<dynamic>? _boxDBInfo;
@ -85,7 +85,8 @@ class DB {
final Map<String, Box<dynamic>> _getSparkUsedCoinsTagsCacheBoxes = {};
// exposed for monero
Box<xmr.WalletInfo> get moneroWalletInfoBox => _walletInfoSource!;
Box<lib_monero_compat.WalletInfo> get moneroWalletInfoBox =>
_walletInfoSource!;
// mutex for stack backup
final mutex = Mutex();
@ -147,8 +148,8 @@ class DB {
_boxTradesV2 = await hive.openBox<Trade>(boxNameTradesV2);
_boxTradeNotes = await hive.openBox<String>(boxNameTradeNotes);
_boxTradeLookup = await hive.openBox<TradeWalletLookup>(boxNameTradeLookup);
_walletInfoSource =
await hive.openBox<xmr.WalletInfo>(xmr.WalletInfo.boxName);
_walletInfoSource = await hive.openBox<lib_monero_compat.WalletInfo>(
lib_monero_compat.WalletInfo.boxName);
_boxFavoriteWallets = await hive.openBox<String>(boxNameFavoriteWallets);
await Future.wait([

View file

@ -13,11 +13,8 @@ import 'dart:io';
import 'dart:math';
import 'package:coinlib_flutter/coinlib_flutter.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:compat/compat.dart' as lib_monero_compat;
import 'package:cs_monero/cs_monero.dart' as lib_monero;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@ -92,10 +89,11 @@ void main(List<String> args) async {
StackFileSystem.setDesktopOverrideDir(args.last);
}
// Tell flutter_libmonero how to get access to the application dir
FS.setApplicationRootDirectoryFunction(
StackFileSystem.applicationRootDirectory,
);
// no longer requried
// // Tell flutter_libmonero how to get access to the application dir
// FS.setApplicationRootDirectoryFunction(
// StackFileSystem.applicationRootDirectory,
// );
// TODO set any other external libs file paths (bad external lib design workaround)
final loadCoinlibFuture = loadCoinlib();
@ -170,15 +168,18 @@ void main(List<String> args) async {
// node model adapter
DB.instance.hive.registerAdapter(NodeModelAdapter());
DB.instance.hive.registerAdapter(NodeAdapter());
// DB.instance.hive.registerAdapter(NodeAdapter());
if (!DB.instance.hive.isAdapterRegistered(WalletInfoAdapter().typeId)) {
DB.instance.hive.registerAdapter(WalletInfoAdapter());
if (!DB.instance.hive
.isAdapterRegistered(lib_monero_compat.WalletInfoAdapter().typeId)) {
DB.instance.hive.registerAdapter(lib_monero_compat.WalletInfoAdapter());
}
DB.instance.hive.registerAdapter(WalletTypeAdapter());
DB.instance.hive.registerAdapter(lib_monero_compat.WalletTypeAdapter());
DB.instance.hive.registerAdapter(UnspentCoinsInfoAdapter());
// DB.instance.hive.registerAdapter(UnspentCoinsInfoAdapter());
lib_monero.Logging.useLogger = true;
DB.instance.hive.init(
(await StackFileSystem.applicationHiveDirectory()).path,

View file

@ -67,7 +67,7 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
late final TextEditingController passwordController;
final bool _nextEnabled = true;
DateTime _restoreFromDate = DateTime.fromMillisecondsSinceEpoch(0);
DateTime? _restoreFromDate;
bool hidePassword = true;
bool _expandedAdavnced = false;

View file

@ -16,10 +16,10 @@ import 'dart:math';
import 'package:bip39/bip39.dart' as bip39;
import 'package:bip39/src/wordlists/english.dart' as bip39wordlist;
import 'package:compat/compat.dart' as lib_monero_compat;
import 'package:cs_monero/cs_monero.dart' as lib_monero;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_libmonero/monero/monero.dart' as libxmr;
import 'package:flutter_libmonero/wownero/wownero.dart' as libwow;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
@ -86,7 +86,7 @@ class RestoreWalletView extends ConsumerStatefulWidget {
final CryptoCurrency coin;
final String mnemonicPassphrase;
final int seedWordsLength;
final DateTime restoreFromDate;
final DateTime? restoreFromDate;
final bool enableLelantusScanning;
final BarcodeScannerInterface barcodeScanner;
@ -181,7 +181,7 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> {
if (widget.coin is Monero) {
switch (widget.seedWordsLength) {
case 25:
return libxmr.monero.getMoneroWordList("English").contains(word);
return lib_monero.getMoneroWordList("English").contains(word);
case 16:
return Monero.sixteenWordsWordList.contains(word);
default:
@ -189,7 +189,7 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> {
}
}
if (widget.coin is Wownero) {
final wowneroWordList = libwow.wownero.getWowneroWordList(
final wowneroWordList = lib_monero.getWowneroWordList(
"English",
seedWordsLength: widget.seedWordsLength,
);
@ -219,29 +219,35 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> {
int height = 0;
String? otherDataJsonString;
if (widget.restoreFromDate != null) {
if (widget.coin is Monero) {
height = libxmr.monero.getHeigthByDate(date: widget.restoreFromDate);
} else if (widget.coin is Wownero) {
height = libwow.wownero.getHeightByDate(date: widget.restoreFromDate);
height = lib_monero_compat.getMoneroHeigthByDate(
date: widget.restoreFromDate!,
);
}
if (widget.coin is Wownero) {
height = lib_monero_compat.getWowneroHeightByDate(
date: widget.restoreFromDate!,
);
}
if (height < 0) {
height = 0;
}
}
// todo: wait until this implemented
// else if (widget.coin is Wownero) {
// height = wownero.getHeightByDate(date: widget.restoreFromDate);
// }
// TODO: make more robust estimate of date maybe using https://explorer.epic.tech/api-index
if (widget.coin is Epiccash) {
if (widget.restoreFromDate != null) {
final int secondsSinceEpoch =
widget.restoreFromDate.millisecondsSinceEpoch ~/ 1000;
widget.restoreFromDate!.millisecondsSinceEpoch ~/ 1000;
const int epicCashFirstBlock = 1565370278;
const double overestimateSecondsPerBlock = 61;
final int chosenSeconds = secondsSinceEpoch - epicCashFirstBlock;
final int approximateHeight =
chosenSeconds ~/ overestimateSecondsPerBlock;
//todo: check if print needed
// debugPrint(
// "approximate height: $approximateHeight chosen_seconds: $chosenSeconds");
height = approximateHeight;
}
if (height < 0) {
height = 0;
}

View file

@ -35,7 +35,7 @@ import '../../wallets/crypto_currency/crypto_currency.dart';
import '../../wallets/isar/providers/wallet_info_provider.dart';
import '../../wallets/models/tx_data.dart';
import '../../wallets/wallet/impl/firo_wallet.dart';
import '../../wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
import '../../wallets/wallet/intermediate/lib_monero_wallet.dart';
import '../../widgets/background.dart';
import '../../widgets/conditional_parent.dart';
import '../../widgets/custom_buttons/app_bar_icon_button.dart';
@ -277,7 +277,7 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
// access to this screen but this is needed to get past an error that
// would occur only to lead to another error which is why xmr/wow wallets
// don't have access to this screen currently
if (wallet is CwBasedInterface) {
if (wallet is LibMoneroWallet) {
await wallet.init();
await wallet.open();
}

View file

@ -26,7 +26,7 @@ import '../../utilities/biometrics.dart';
import '../../utilities/flutter_secure_storage_interface.dart';
import '../../utilities/show_loading.dart';
import '../../utilities/text_styles.dart';
import '../../wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
import '../../wallets/wallet/intermediate/lib_monero_wallet.dart';
import '../../widgets/background.dart';
import '../../widgets/custom_buttons/app_bar_icon_button.dart';
import '../../widgets/custom_buttons/blue_text_button.dart';
@ -102,7 +102,7 @@ class _LockscreenViewState extends ConsumerState<LockscreenView> {
final wallet = ref.read(pWallets).getWallet(walletId);
final Future<void> loadFuture;
if (wallet is CwBasedInterface) {
if (wallet is LibMoneroWallet) {
loadFuture =
wallet.init().then((value) async => await (wallet).open());
} else {

View file

@ -11,10 +11,10 @@
import 'dart:async';
import 'dart:io';
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:cs_monero/cs_monero.dart' as lib_monero;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:tuple/tuple.dart';
@ -470,22 +470,22 @@ class _SendViewState extends ConsumerState<SendView> {
Amount fee;
if (coin is Monero) {
MoneroTransactionPriority specialMoneroId;
lib_monero.TransactionPriority specialMoneroId;
switch (ref.read(feeRateTypeStateProvider.state).state) {
case FeeRateType.fast:
specialMoneroId = MoneroTransactionPriority.fast;
specialMoneroId = lib_monero.TransactionPriority.high;
break;
case FeeRateType.average:
specialMoneroId = MoneroTransactionPriority.regular;
specialMoneroId = lib_monero.TransactionPriority.medium;
break;
case FeeRateType.slow:
specialMoneroId = MoneroTransactionPriority.slow;
specialMoneroId = lib_monero.TransactionPriority.normal;
break;
default:
throw ArgumentError("custom fee not available for monero");
}
fee = await wallet.estimateFeeFor(amount, specialMoneroId.raw!);
fee = await wallet.estimateFeeFor(amount, specialMoneroId.value);
cachedFees[amount] = ref.read(pAmountFormatter(coin)).format(
fee,
withUnitName: true,

View file

@ -8,9 +8,10 @@
*
*/
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:flutter/material.dart';
import 'package:cs_monero/cs_monero.dart' as lib_monero;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../models/paymint/fee_object_model.dart';
import '../../../providers/providers.dart';
import '../../../providers/ui/fee_rate_type_state_provider.dart';
@ -90,7 +91,7 @@ class _TransactionFeeSelectionSheetState
if (coin is Monero || coin is Wownero) {
final fee = await wallet.estimateFeeFor(
amount,
MoneroTransactionPriority.fast.raw!,
lib_monero.TransactionPriority.high.value,
);
ref.read(feeSheetSessionCacheProvider).fast[amount] = fee;
} else if (coin is Firo) {
@ -127,7 +128,7 @@ class _TransactionFeeSelectionSheetState
if (coin is Monero || coin is Wownero) {
final fee = await wallet.estimateFeeFor(
amount,
MoneroTransactionPriority.regular.raw!,
lib_monero.TransactionPriority.medium.value,
);
ref.read(feeSheetSessionCacheProvider).average[amount] = fee;
} else if (coin is Firo) {
@ -163,7 +164,7 @@ class _TransactionFeeSelectionSheetState
if (coin is Monero || coin is Wownero) {
final fee = await wallet.estimateFeeFor(
amount,
MoneroTransactionPriority.slow.raw!,
lib_monero.TransactionPriority.normal.value,
);
ref.read(feeSheetSessionCacheProvider).slow[amount] = fee;
} else if (coin is Firo) {

View file

@ -272,48 +272,48 @@ class AboutView extends ConsumerWidget {
const SizedBox(
height: 12,
),
if (AppConfig.coins.whereType<Monero>().isNotEmpty)
FutureBuilder(
future: GitStatus.getMoneroCommitStatus(),
builder: (
context,
AsyncSnapshot<CommitStatus> snapshot,
) {
CommitStatus stateOfCommit =
CommitStatus.notLoaded;
if (snapshot.connectionState ==
ConnectionState.done &&
snapshot.hasData) {
stateOfCommit = snapshot.data!;
}
return RoundedWhiteContainer(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
Text(
"Monero Build Commit",
style: STextStyles.titleBold12(context),
),
const SizedBox(
height: 4,
),
SelectableText(
GitStatus.moneroCommit,
style: GitStatus.styleForStatus(
stateOfCommit,
context,
),
),
],
),
);
},
),
const SizedBox(
height: 12,
),
// if (AppConfig.coins.whereType<Monero>().isNotEmpty)
// FutureBuilder(
// future: GitStatus.getMoneroCommitStatus(),
// builder: (
// context,
// AsyncSnapshot<CommitStatus> snapshot,
// ) {
// CommitStatus stateOfCommit =
// CommitStatus.notLoaded;
//
// if (snapshot.connectionState ==
// ConnectionState.done &&
// snapshot.hasData) {
// stateOfCommit = snapshot.data!;
// }
// return RoundedWhiteContainer(
// child: Column(
// crossAxisAlignment:
// CrossAxisAlignment.stretch,
// children: [
// Text(
// "Monero Build Commit",
// style: STextStyles.titleBold12(context),
// ),
// const SizedBox(
// height: 4,
// ),
// SelectableText(
// GitStatus.moneroCommit,
// style: GitStatus.styleForStatus(
// stateOfCommit,
// context,
// ),
// ),
// ],
// ),
// );
// },
// ),
// const SizedBox(
// height: 12,
// ),
RoundedWhiteContainer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,

View file

@ -18,7 +18,7 @@ import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_libepiccash/git_versions.dart' as EPIC_VERSIONS;
import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS;
// import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:lelantus/git_versions.dart' as FIRO_VERSIONS;
@ -313,8 +313,8 @@ class _DebugViewState extends ConsumerState<DebugView> {
FIRO_VERSIONS.getPluginVersion();
final String epicCashCommit =
EPIC_VERSIONS.getPluginVersion();
final String moneroCommit =
MONERO_VERSIONS.getPluginVersion();
// final String moneroCommit =
// MONERO_VERSIONS.getPluginVersion();
final DeviceInfoPlugin deviceInfoPlugin =
DeviceInfoPlugin();
final deviceInfo =
@ -347,7 +347,7 @@ class _DebugViewState extends ConsumerState<DebugView> {
"appName": appName,
"firoCommit": firoCommit,
"epicCashCommit": epicCashCommit,
"moneroCommit": moneroCommit,
// "moneroCommit": moneroCommit,
"deviceInfoMap": deviceInfoMap,
"errorLogs": errorLogs,
};

View file

@ -29,7 +29,7 @@ import '../../../../utilities/text_styles.dart';
import '../../../../utilities/util.dart';
import '../../../../wallets/crypto_currency/crypto_currency.dart';
import '../../../../wallets/crypto_currency/intermediate/cryptonote_currency.dart';
import '../../../../wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
import '../../../../wallets/wallet/intermediate/lib_monero_wallet.dart';
import '../../../../widgets/background.dart';
import '../../../../widgets/conditional_parent.dart';
import '../../../../widgets/custom_buttons/app_bar_icon_button.dart';
@ -222,7 +222,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
// strip unused path
String address = formData.host!;
if (coin is CwBasedInterface) {
if (coin is LibMoneroWallet) {
if (address.startsWith("http")) {
final uri = Uri.parse(address);
address = "${uri.scheme}://${uri.host}";
@ -837,7 +837,7 @@ class _NodeFormState extends ConsumerState<NodeForm> {
} else {
enableSSLCheckbox = true;
}
} else if (widget.coin is CwBasedInterface) {
} else if (widget.coin is LibMoneroWallet) {
if (newValue.startsWith("https://")) {
_useSSL = true;
} else if (newValue.startsWith("http://")) {
@ -1052,7 +1052,7 @@ class _NodeFormState extends ConsumerState<NodeForm> {
),
],
),
if (widget.coin is CwBasedInterface)
if (widget.coin is LibMoneroWallet)
Row(
children: [
GestureDetector(

View file

@ -54,8 +54,8 @@ import '../../../../../wallets/wallet/impl/bitcoin_frost_wallet.dart';
import '../../../../../wallets/wallet/impl/epiccash_wallet.dart';
import '../../../../../wallets/wallet/impl/monero_wallet.dart';
import '../../../../../wallets/wallet/impl/wownero_wallet.dart';
import '../../../../../wallets/wallet/intermediate/lib_monero_wallet.dart';
import '../../../../../wallets/wallet/wallet.dart';
import '../../../../../wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
import '../../../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
import '../../../../../wallets/wallet/wallet_mixin_interfaces/private_key_interface.dart';
@ -503,7 +503,7 @@ abstract class SWB {
Future<void>? restoringFuture;
if (!(wallet is CwBasedInterface || wallet is EpiccashWallet)) {
if (!(wallet is LibMoneroWallet || wallet is EpiccashWallet)) {
if (wallet is BitcoinFrostWallet) {
restoringFuture = wallet.recover(
isRescan: false,

View file

@ -36,7 +36,7 @@ import '../../../wallets/crypto_currency/intermediate/frost_currency.dart';
import '../../../wallets/crypto_currency/intermediate/nano_currency.dart';
import '../../../wallets/wallet/impl/bitcoin_frost_wallet.dart';
import '../../../wallets/wallet/impl/epiccash_wallet.dart';
import '../../../wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
import '../../../wallets/wallet/intermediate/lib_monero_wallet.dart';
import '../../../wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart';
import '../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
import '../../../widgets/background.dart';
@ -307,7 +307,7 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
KeyDataInterface? keyData;
if (wallet is ExtendedKeysInterface) {
keyData = await wallet.getXPrivs();
} else if (wallet is CwBasedInterface) {
} else if (wallet is LibMoneroWallet) {
keyData = await wallet.getKeys();
}

View file

@ -12,7 +12,7 @@ import '../../utilities/assets.dart';
import '../../utilities/text_styles.dart';
import '../../utilities/util.dart';
import '../../wallets/isar/providers/wallet_info_provider.dart';
import '../../wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
import '../../wallets/wallet/intermediate/lib_monero_wallet.dart';
import '../../wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart';
import '../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
import '../../widgets/background.dart';
@ -270,7 +270,7 @@ class _FiroRescanRecoveryErrorViewState
KeyDataInterface? keyData;
if (wallet is ExtendedKeysInterface) {
keyData = await wallet.getXPrivs();
} else if (wallet is CwBasedInterface) {
} else if (wallet is LibMoneroWallet) {
keyData = await wallet.getKeys();
}

View file

@ -13,7 +13,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../../wallet_view/wallet_view.dart';
import '../../../pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart';
import '../../../providers/providers.dart';
import '../../../themes/coin_icon_provider.dart';
@ -26,9 +26,10 @@ import '../../../utilities/text_styles.dart';
import '../../../utilities/util.dart';
import '../../../wallets/crypto_currency/coins/firo.dart';
import '../../../wallets/isar/providers/wallet_info_provider.dart';
import '../../../wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
import '../../../wallets/wallet/intermediate/lib_monero_wallet.dart';
import '../../../widgets/coin_card.dart';
import '../../../widgets/conditional_parent.dart';
import '../../wallet_view/wallet_view.dart';
class FavoriteCard extends ConsumerStatefulWidget {
const FavoriteCard({
@ -117,7 +118,7 @@ class _FavoriteCardState extends ConsumerState<FavoriteCard> {
final wallet = ref.read(pWallets).getWallet(walletId);
final Future<void> loadFuture;
if (wallet is CwBasedInterface) {
if (wallet is LibMoneroWallet) {
loadFuture =
wallet.init().then((value) async => await (wallet).open());
} else {

View file

@ -24,7 +24,7 @@ import '../../../utilities/show_loading.dart';
import '../../../utilities/text_styles.dart';
import '../../../utilities/util.dart';
import '../../../wallets/crypto_currency/crypto_currency.dart';
import '../../../wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
import '../../../wallets/wallet/intermediate/lib_monero_wallet.dart';
import '../../../widgets/dialogs/tor_warning_dialog.dart';
import '../../../widgets/rounded_white_container.dart';
import '../../wallet_view/wallet_view.dart';
@ -84,7 +84,7 @@ class WalletListItem extends ConsumerWidget {
.wallets
.firstWhere((e) => e.info.coin == coin);
final Future<void> loadFuture;
if (wallet is CwBasedInterface) {
if (wallet is LibMoneroWallet) {
loadFuture =
wallet.init().then((value) async => await (wallet).open());
} else {

View file

@ -10,7 +10,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'wallet_view/desktop_wallet_view.dart';
import '../../providers/global/active_wallet_provider.dart';
import '../../providers/global/wallets_provider.dart';
import '../../themes/stack_colors.dart';
@ -18,9 +18,10 @@ import '../../utilities/constants.dart';
import '../../utilities/show_loading.dart';
import '../../utilities/util.dart';
import '../../wallets/crypto_currency/crypto_currency.dart';
import '../../wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
import '../../wallets/wallet/intermediate/lib_monero_wallet.dart';
import '../../widgets/rounded_container.dart';
import '../../widgets/wallet_info_row/wallet_info_row.dart';
import 'wallet_view/desktop_wallet_view.dart';
class CoinWalletsTable extends ConsumerWidget {
const CoinWalletsTable({
@ -81,7 +82,7 @@ class CoinWalletsTable extends ConsumerWidget {
final wallet =
ref.read(pWallets).getWallet(walletIds[i]);
final Future<void> loadFuture;
if (wallet is CwBasedInterface) {
if (wallet is LibMoneroWallet) {
loadFuture = wallet
.init()
.then((value) async => await (wallet).open());

View file

@ -8,9 +8,9 @@
*
*/
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:cs_monero/cs_monero.dart' as lib_monero;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
@ -86,7 +86,7 @@ class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> {
if (coin is Monero || coin is Wownero) {
final fee = await wallet.estimateFeeFor(
amount,
MoneroTransactionPriority.fast.raw!,
lib_monero.TransactionPriority.high.value,
);
ref.read(feeSheetSessionCacheProvider).fast[amount] = fee;
} else if (coin is Firo) {
@ -136,7 +136,7 @@ class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> {
if (coin is Monero || coin is Wownero) {
final fee = await wallet.estimateFeeFor(
amount,
MoneroTransactionPriority.regular.raw!,
lib_monero.TransactionPriority.medium.value,
);
ref.read(feeSheetSessionCacheProvider).average[amount] = fee;
} else if (coin is Firo) {
@ -186,7 +186,7 @@ class _DesktopFeeDropDownState extends ConsumerState<DesktopFeeDropDown> {
if (coin is Monero || coin is Wownero) {
final fee = await wallet.estimateFeeFor(
amount,
MoneroTransactionPriority.slow.raw!,
lib_monero.TransactionPriority.normal.value,
);
ref.read(feeSheetSessionCacheProvider).slow[amount] = fee;
} else if (coin is Firo) {

View file

@ -10,11 +10,11 @@
import 'dart:async';
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:decimal/decimal.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:cs_monero/cs_monero.dart' as lib_monero;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
@ -1860,7 +1860,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
if (coin is Monero || coin is Wownero) {
final fee = await wallet.estimateFeeFor(
amount,
MoneroTransactionPriority.regular.raw!,
lib_monero.TransactionPriority.medium.value,
);
ref
.read(feeSheetSessionCacheProvider)

View file

@ -23,7 +23,7 @@ import '../../../../utilities/assets.dart';
import '../../../../utilities/constants.dart';
import '../../../../utilities/text_styles.dart';
import '../../../../wallets/wallet/impl/bitcoin_frost_wallet.dart';
import '../../../../wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
import '../../../../wallets/wallet/intermediate/lib_monero_wallet.dart';
import '../../../../wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart';
import '../../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
import '../../../../widgets/desktop/desktop_dialog.dart';
@ -106,7 +106,7 @@ class _UnlockWalletKeysDesktopState
KeyDataInterface? keyData;
if (wallet is ExtendedKeysInterface) {
keyData = await wallet.getXPrivs();
} else if (wallet is CwBasedInterface) {
} else if (wallet is LibMoneroWallet) {
keyData = await wallet.getKeys();
}
@ -353,7 +353,7 @@ class _UnlockWalletKeysDesktopState
KeyDataInterface? keyData;
if (wallet is ExtendedKeysInterface) {
keyData = await wallet.getXPrivs();
} else if (wallet is CwBasedInterface) {
} else if (wallet is LibMoneroWallet) {
keyData = await wallet.getKeys();
}

View file

@ -434,63 +434,63 @@ class DesktopAboutView extends ConsumerWidget {
);
},
),
if (AppConfig.coins
.whereType<Monero>()
.isNotEmpty)
FutureBuilder(
future: GitStatus
.getMoneroCommitStatus(),
builder: (
context,
AsyncSnapshot<CommitStatus>
snapshot,
) {
CommitStatus stateOfCommit =
CommitStatus.notLoaded;
if (snapshot.connectionState ==
ConnectionState
.done &&
snapshot.hasData) {
stateOfCommit =
snapshot.data!;
}
return Column(
mainAxisSize:
MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Text(
"Monero Build Commit",
style: STextStyles
.desktopTextExtraExtraSmall(
context,
).copyWith(
color: Theme.of(
context,
)
.extension<
StackColors>()!
.textDark,
),
),
const SizedBox(
height: 2,
),
SelectableText(
GitStatus.moneroCommit,
style: GitStatus
.styleForStatus(
stateOfCommit,
context,
),
),
],
);
},
),
// if (AppConfig.coins
// .whereType<Monero>()
// .isNotEmpty)
// FutureBuilder(
// future: GitStatus
// .getMoneroCommitStatus(),
// builder: (
// context,
// AsyncSnapshot<CommitStatus>
// snapshot,
// ) {
// CommitStatus stateOfCommit =
// CommitStatus.notLoaded;
//
// if (snapshot.connectionState ==
// ConnectionState
// .done &&
// snapshot.hasData) {
// stateOfCommit =
// snapshot.data!;
// }
// return Column(
// mainAxisSize:
// MainAxisSize.min,
// crossAxisAlignment:
// CrossAxisAlignment
// .start,
// children: [
// Text(
// "Monero Build Commit",
// style: STextStyles
// .desktopTextExtraExtraSmall(
// context,
// ).copyWith(
// color: Theme.of(
// context,
// )
// .extension<
// StackColors>()!
// .textDark,
// ),
// ),
// const SizedBox(
// height: 2,
// ),
// SelectableText(
// GitStatus.moneroCommit,
// style: GitStatus
// .styleForStatus(
// stateOfCommit,
// context,
// ),
// ),
// ],
// );
// },
// ),
],
),
const SizedBox(height: 35),

View file

@ -1456,7 +1456,7 @@ class RouteGenerator {
case RestoreWalletView.routeName:
if (args
is Tuple6<String, CryptoCurrency, int, DateTime, String, bool>) {
is Tuple6<String, CryptoCurrency, int, DateTime?, String, bool>) {
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => RestoreWalletView(

View file

@ -10,8 +10,7 @@
import 'dart:async';
import 'package:flutter_libmonero/monero/monero.dart' as monero;
import 'package:flutter_libmonero/wownero/wownero.dart' as wownero;
import 'package:compat/compat.dart' as lib_monero_compat;
import 'package:isar/isar.dart';
import '../app_config.dart';
@ -21,11 +20,12 @@ import '../utilities/enums/sync_type_enum.dart';
import '../utilities/flutter_secure_storage_interface.dart';
import '../utilities/logger.dart';
import '../utilities/prefs.dart';
import '../utilities/stack_file_system.dart';
import '../wallets/crypto_currency/crypto_currency.dart';
import '../wallets/isar/models/wallet_info.dart';
import '../wallets/wallet/impl/epiccash_wallet.dart';
import '../wallets/wallet/intermediate/lib_monero_wallet.dart';
import '../wallets/wallet/wallet.dart';
import '../wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
import 'event_bus/events/wallet_added_event.dart';
import 'event_bus/global_event_bus.dart';
import 'node_service.dart';
@ -86,15 +86,19 @@ class Wallets {
await secureStorage.delete(key: Wallet.privateKeyKey(walletId: walletId));
if (info.coin is Wownero) {
final wowService = wownero.wownero
.createWowneroWalletService(DB.instance.moneroWalletInfoBox);
await wowService.remove(walletId);
await lib_monero_compat.deleteWalletFiles(
name: walletId,
type: lib_monero_compat.WalletType.wownero,
appRoot: await StackFileSystem.applicationRootDirectory(),
);
Logging.instance
.log("monero wallet: $walletId deleted", level: LogLevel.Info);
} else if (info.coin is Monero) {
final xmrService = monero.monero
.createMoneroWalletService(DB.instance.moneroWalletInfoBox);
await xmrService.remove(walletId);
await lib_monero_compat.deleteWalletFiles(
name: walletId,
type: lib_monero_compat.WalletType.monero,
appRoot: await StackFileSystem.applicationRootDirectory(),
);
Logging.instance
.log("monero wallet: $walletId deleted", level: LogLevel.Info);
} else if (info.coin is Epiccash) {
@ -220,7 +224,7 @@ class Wallets {
final shouldSetAutoSync = shouldAutoSyncAll ||
walletIdsToEnableAutoSync.contains(walletInfo.walletId);
if (wallet is CwBasedInterface) {
if (wallet is LibMoneroWallet) {
// walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
} else {
walletInitFutures.add(
@ -327,7 +331,7 @@ class Wallets {
nodeService: nodeService,
prefs: prefs,
).then((wallet) {
if (wallet is CwBasedInterface) {
if (wallet is LibMoneroWallet) {
// walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
walletIdCompleter.complete("dummy_ignore");
@ -457,7 +461,7 @@ class Wallets {
nodeService: nodeService,
prefs: prefs,
).then((wallet) {
if (wallet is CwBasedInterface) {
if (wallet is LibMoneroWallet) {
// walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
walletIdCompleter.complete("dummy_ignore");
@ -577,7 +581,7 @@ class Wallets {
walletIdsToEnableAutoSync.contains(wallet.walletId);
if (isDesktop) {
if (wallet is CwBasedInterface) {
if (wallet is LibMoneroWallet) {
// walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
} else {
walletInitFutures.add(

View file

@ -2,7 +2,7 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_libepiccash/git_versions.dart' as epic_versions;
import 'package:flutter_libmonero/git_versions.dart' as monero_versions;
// import 'package:flutter_libmonero/git_versions.dart' as monero_versions;
import 'package:http/http.dart';
import 'package:lelantus/git_versions.dart' as firo_versions;
@ -20,7 +20,7 @@ enum CommitStatus { isHead, isOldCommit, notACommit, notLoaded }
abstract class GitStatus {
static String get firoCommit => firo_versions.getPluginVersion();
static String get epicCashCommit => epic_versions.getPluginVersion();
static String get moneroCommit => monero_versions.getPluginVersion();
// static String get moneroCommit => monero_versions.getPluginVersion();
static String get appCommitHash => AppConfig.commitHash;
@ -78,31 +78,31 @@ abstract class GitStatus {
return _cachedEpicStatus!;
}
static CommitStatus? _cachedMoneroStatus;
static Future<CommitStatus> getMoneroCommitStatus() async {
if (_cachedMoneroStatus != null) {
return _cachedMoneroStatus!;
}
final List<bool> results = await Future.wait([
_doesCommitExist("cypherstack", "flutter_libmonero", moneroCommit),
_isHeadCommit("cypherstack", "flutter_libmonero", "main", moneroCommit),
]);
final commitExists = results[0];
final commitIsHead = results[1];
if (commitExists && commitIsHead) {
_cachedMoneroStatus = CommitStatus.isHead;
} else if (commitExists) {
_cachedMoneroStatus = CommitStatus.isOldCommit;
} else {
_cachedMoneroStatus = CommitStatus.notACommit;
}
return _cachedMoneroStatus!;
}
//
// static CommitStatus? _cachedMoneroStatus;
// static Future<CommitStatus> getMoneroCommitStatus() async {
// if (_cachedMoneroStatus != null) {
// return _cachedMoneroStatus!;
// }
//
// final List<bool> results = await Future.wait([
// _doesCommitExist("cypherstack", "flutter_libmonero", moneroCommit),
// _isHeadCommit("cypherstack", "flutter_libmonero", "main", moneroCommit),
// ]);
//
// final commitExists = results[0];
// final commitIsHead = results[1];
//
// if (commitExists && commitIsHead) {
// _cachedMoneroStatus = CommitStatus.isHead;
// } else if (commitExists) {
// _cachedMoneroStatus = CommitStatus.isOldCommit;
// } else {
// _cachedMoneroStatus = CommitStatus.notACommit;
// }
//
// return _cachedMoneroStatus!;
// }
static TextStyle styleForStatus(CommitStatus status, BuildContext context) {
final Color color;

View file

@ -1,5 +1,4 @@
import 'package:cw_monero/pending_monero_transaction.dart';
import 'package:cw_wownero/pending_wownero_transaction.dart';
import 'package:cs_monero/cs_monero.dart' as lib_monero;
import 'package:tezart/tezart.dart' as tezart;
import 'package:web3dart/web3dart.dart' as web3dart;
@ -49,11 +48,8 @@ class TxData {
final BigInt? chainId;
final BigInt? feeInWei;
// wownero specific
final PendingWowneroTransaction? pendingWowneroTransaction;
// monero specific
final PendingMoneroTransaction? pendingMoneroTransaction;
// wownero and monero specific
final lib_monero.PendingTransaction? pendingTransaction;
// firo lelantus specific
final int? jMintValue;
@ -104,8 +100,7 @@ class TxData {
this.nonce,
this.chainId,
this.feeInWei,
this.pendingWowneroTransaction,
this.pendingMoneroTransaction,
this.pendingTransaction,
this.jMintValue,
this.spendCoinIndexes,
this.height,
@ -196,8 +191,7 @@ class TxData {
int? nonce,
BigInt? chainId,
BigInt? feeInWei,
PendingWowneroTransaction? pendingWowneroTransaction,
PendingMoneroTransaction? pendingMoneroTransaction,
lib_monero.PendingTransaction? pendingTransaction,
int? jMintValue,
List<int>? spendCoinIndexes,
int? height,
@ -241,10 +235,7 @@ class TxData {
nonce: nonce ?? this.nonce,
chainId: chainId ?? this.chainId,
feeInWei: feeInWei ?? this.feeInWei,
pendingWowneroTransaction:
pendingWowneroTransaction ?? this.pendingWowneroTransaction,
pendingMoneroTransaction:
pendingMoneroTransaction ?? this.pendingMoneroTransaction,
pendingTransaction: pendingTransaction ?? this.pendingTransaction,
jMintValue: jMintValue ?? this.jMintValue,
spendCoinIndexes: spendCoinIndexes ?? this.spendCoinIndexes,
height: height ?? this.height,
@ -284,8 +275,7 @@ class TxData {
'nonce: $nonce, '
'chainId: $chainId, '
'feeInWei: $feeInWei, '
'pendingWowneroTransaction: $pendingWowneroTransaction, '
'pendingMoneroTransaction: $pendingMoneroTransaction, '
'pendingTransaction: $pendingTransaction, '
'jMintValue: $jMintValue, '
'spendCoinIndexes: $spendCoinIndexes, '
'height: $height, '

View file

@ -1,206 +1,51 @@
import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/utxo.dart' as cw;
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart';
import 'package:cw_monero/monero_wallet.dart';
import 'package:cw_monero/monero_wallet_service.dart';
import 'package:cw_monero/pending_monero_transaction.dart';
import 'package:decimal/decimal.dart';
import 'package:flutter_libmonero/core/wallet_creation_service.dart';
import 'package:flutter_libmonero/monero/monero.dart' as xmr_dart;
import 'package:flutter_libmonero/view_model/send/output.dart' as monero_output;
import 'package:isar/isar.dart';
import 'package:mutex/mutex.dart';
import 'package:tuple/tuple.dart';
import 'package:compat/compat.dart' as lib_monero_compat;
import 'package:cs_monero/cs_monero.dart' as lib_monero;
import '../../../db/hive/db.dart';
import '../../../models/isar/models/blockchain_data/address.dart';
import '../../../models/isar/models/blockchain_data/transaction.dart';
import '../../../models/isar/models/blockchain_data/utxo.dart';
import '../../../models/keys/cw_key_data.dart';
import '../../../services/event_bus/events/global/tor_connection_status_changed_event.dart';
import '../../../services/event_bus/events/global/tor_status_changed_event.dart';
import '../../../services/event_bus/global_event_bus.dart';
import '../../../services/tor_service.dart';
import '../../../utilities/amount/amount.dart';
import '../../../utilities/enums/fee_rate_type_enum.dart';
import '../../../utilities/logger.dart';
import '../../crypto_currency/crypto_currency.dart';
import '../../models/tx_data.dart';
import '../intermediate/cryptonote_wallet.dart';
import '../wallet.dart';
import '../wallet_mixin_interfaces/cw_based_interface.dart';
import '../intermediate/lib_monero_wallet.dart';
class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
MoneroWallet(CryptoCurrencyNetwork network) : super(Monero(network)) {
final bus = GlobalEventBus.instance;
// Listen for tor status changes.
_torStatusListener = bus.on<TorConnectionStatusChangedEvent>().listen(
(event) async {
switch (event.newStatus) {
case TorConnectionStatus.connecting:
if (!_torConnectingLock.isLocked) {
await _torConnectingLock.acquire();
}
_requireMutex = true;
break;
case TorConnectionStatus.connected:
case TorConnectionStatus.disconnected:
if (_torConnectingLock.isLocked) {
_torConnectingLock.release();
}
_requireMutex = false;
break;
}
},
class MoneroWallet extends LibMoneroWallet {
MoneroWallet(CryptoCurrencyNetwork network)
: super(
Monero(network),
lib_monero_compat.WalletType.monero,
);
// Listen for tor preference changes.
_torPreferenceListener = bus.on<TorPreferenceChangedEvent>().listen(
(event) async {
await updateNode();
},
);
// Potentially dangerous hack. See comments in _startInit()
_startInit();
}
// cw based wallet listener to handle synchronization of utxo frozen states
late final StreamSubscription<List<UTXO>> _streamSub;
Future<void> _startInit() async {
// Delay required as `mainDB` is not initialized in constructor.
// This is a hack and could lead to a race condition.
Future.delayed(const Duration(seconds: 2), () {
_streamSub = mainDB.isar.utxos
.where()
.walletIdEqualTo(walletId)
.watch(fireImmediately: true)
.listen((utxos) async {
await onUTXOsCHanged(utxos);
await updateBalance(shouldUpdateUtxos: false);
});
});
}
@override
MoneroWalletBase? cwWalletBase;
@override
MoneroWalletService? cwWalletService;
@override
Address addressFor({required int index, int account = 0}) {
final String address = (cwWalletBase as MoneroWalletBase)
.getTransactionAddress(account, index);
final newReceivingAddress = Address(
walletId: walletId,
derivationIndex: index,
derivationPath: null,
value: address,
publicKey: [],
type: AddressType.cryptonote,
subType: AddressSubType.receiving,
);
return newReceivingAddress;
}
@override
Future<void> open() async {
String? password;
try {
password = await cwKeysStorage.getWalletPassword(walletName: walletId);
} catch (e, s) {
throw Exception("Password not found $e, $s");
}
bool wasNull = false;
if (cwWalletBase == null) {
wasNull = true;
// cwWalletBaseT?.close();
cwWalletBase ??= (await cwWalletService!.openWallet(walletId, password))
as MoneroWalletBase;
cwWalletBase?.onNewBlock ??= onNewBlock;
cwWalletBase?.onNewTransaction ??= onNewTransaction;
cwWalletBase?.syncStatusChanged ??= syncStatusChanged;
await updateNode();
}
Address? currentAddress = await getCurrentReceivingAddress();
if (currentAddress == null) {
currentAddress = addressFor(index: 0);
await mainDB.updateOrPutAddresses([currentAddress]);
}
if (info.cachedReceivingAddress != currentAddress.value) {
await info.updateReceivingAddress(
newAddress: currentAddress.value,
isar: mainDB.isar,
);
}
if (wasNull) {
await cwWalletBase?.startSync();
} else {
cwWalletBase?.wallet.startListeners();
}
unawaited(refresh());
autoSaveTimer?.cancel();
autoSaveTimer = Timer.periodic(
const Duration(seconds: 193),
(_) async => await cwWalletBase?.save(),
);
}
@override
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
if (cwWalletBase == null || cwWalletBase?.syncStatus is! SyncedSyncStatus) {
if (libMoneroWallet == null ||
syncStatus is! lib_monero_compat.SyncedSyncStatus) {
return Amount.zeroWith(
fractionDigits: cryptoCurrency.fractionDigits,
);
}
MoneroTransactionPriority priority;
lib_monero.TransactionPriority priority;
switch (feeRate) {
case 1:
priority = MoneroTransactionPriority.regular;
priority = lib_monero.TransactionPriority.low;
break;
case 2:
priority = MoneroTransactionPriority.medium;
priority = lib_monero.TransactionPriority.medium;
break;
case 3:
priority = MoneroTransactionPriority.fast;
priority = lib_monero.TransactionPriority.high;
break;
case 4:
priority = MoneroTransactionPriority.fastest;
priority = lib_monero.TransactionPriority.last;
break;
case 0:
default:
priority = MoneroTransactionPriority.slow;
priority = lib_monero.TransactionPriority.normal;
break;
}
int approximateFee = 0;
await estimateFeeMutex.protect(() async {
approximateFee = cwWalletBase!.calculateEstimatedFee(
approximateFee = await libMoneroWallet!.estimateFee(
priority,
amount.raw.toInt(),
);
@ -213,573 +58,49 @@ class MoneroWallet extends CryptonoteWallet with CwBasedInterface {
}
@override
Future<bool> pingCheck() async {
return await cwWalletBase?.isConnected() ?? false;
}
bool walletExists(String path) => lib_monero.MoneroWallet.isWalletExist(path);
@override
Future<void> updateNode() async {
final node = getCurrentNode();
String host = Uri.parse(node.host).host;
if (host.isEmpty) {
host = node.host;
}
({InternetAddress host, int port})? proxy;
if (prefs.useTor) {
proxy = TorService.sharedInstance.getProxyInfo();
}
if (_requireMutex) {
await _torConnectingLock.protect(() async {
await cwWalletBase?.connectToNode(
node: Node(
uri: "$host:${node.port}",
type: WalletType.monero,
trusted: node.trusted ?? false,
useSSL: node.useSSL,
),
socksProxyAddress:
proxy == null ? null : "${proxy.host.address}:${proxy.port}",
);
});
} else {
await cwWalletBase?.connectToNode(
node: Node(
uri: "$host:${node.port}",
type: WalletType.monero,
trusted: node.trusted ?? false,
useSSL: node.useSSL,
),
socksProxyAddress:
proxy == null ? null : "${proxy.host.address}:${proxy.port}",
);
}
return;
}
@override
Future<CWKeyData?> getKeys() async {
final base = cwWalletBase;
if (base == null || base.walletInfo.name != walletId) {
return null;
}
return CWKeyData(
walletId: walletId,
publicViewKey: base.keys.publicViewKey,
privateViewKey: base.keys.privateViewKey,
publicSpendKey: base.keys.publicSpendKey,
privateSpendKey: base.keys.privateSpendKey,
);
}
@override
Future<void> updateTransactions() async {
final base = cwWalletBase;
if (base == null || base.walletInfo.name != walletId) {
return;
}
await base.updateTransactions();
final transactions = base.transactionHistory?.transactions;
// final cachedTransactions =
// DB.instance.get<dynamic>(boxName: walletId, key: 'latest_tx_model')
// as TransactionData?;
// int latestTxnBlockHeight =
// DB.instance.get<dynamic>(boxName: walletId, key: "storedTxnDataHeight")
// as int? ??
// 0;
//
// final txidsList = DB.instance
// .get<dynamic>(boxName: walletId, key: "cachedTxids") as List? ??
// [];
//
// final Set<String> cachedTxids = Set<String>.from(txidsList);
// TODO: filter to skip cached + confirmed txn processing in next step
// final unconfirmedCachedTransactions =
// cachedTransactions?.getAllTransactions() ?? {};
// unconfirmedCachedTransactions
// .removeWhere((key, value) => value.confirmedStatus);
//
// if (cachedTransactions != null) {
// for (final tx in allTxHashes.toList(growable: false)) {
// final txHeight = tx["height"] as int;
// if (txHeight > 0 &&
// txHeight < latestTxnBlockHeight - MINIMUM_CONFIRMATIONS) {
// if (unconfirmedCachedTransactions[tx["tx_hash"] as String] == null) {
// allTxHashes.remove(tx);
// }
// }
// }
// }
final List<Tuple2<Transaction, Address?>> txnsData = [];
if (transactions != null) {
for (final tx in transactions.entries) {
Address? address;
TransactionType type;
if (tx.value.direction == TransactionDirection.incoming) {
final addressInfo = tx.value.additionalInfo;
final addressString = cwWalletBase?.getTransactionAddress(
addressInfo!['accountIndex'] as int,
addressInfo['addressIndex'] as int,
);
if (addressString != null) {
address = await mainDB
.getAddresses(walletId)
.filter()
.valueEqualTo(addressString)
.findFirst();
}
type = TransactionType.incoming;
} else {
// txn.address = "";
type = TransactionType.outgoing;
}
final txn = Transaction(
walletId: walletId,
txid: tx.value.id,
timestamp: (tx.value.date.millisecondsSinceEpoch ~/ 1000),
type: type,
subType: TransactionSubType.none,
amount: tx.value.amount ?? 0,
amountString: Amount(
rawValue: BigInt.from(tx.value.amount ?? 0),
fractionDigits: cryptoCurrency.fractionDigits,
).toJsonString(),
fee: tx.value.fee ?? 0,
height: tx.value.height,
isCancelled: false,
isLelantus: false,
slateId: null,
otherData: null,
nonce: null,
inputs: [],
outputs: [],
numberOfMessages: null,
);
txnsData.add(Tuple2(txn, address));
}
}
await mainDB.isar.writeTxn(() async {
await mainDB.isar.transactions
.where()
.walletIdEqualTo(walletId)
.deleteAll();
for (final data in txnsData) {
final tx = data.item1;
// save transaction
await mainDB.isar.transactions.put(tx);
if (data.item2 != null) {
final address = await mainDB.getAddress(walletId, data.item2!.value);
// check if address exists in db and add if it does not
if (address == null) {
await mainDB.isar.addresses.put(data.item2!);
}
// link and save address
tx.address.value = address ?? data.item2!;
await tx.address.save();
}
}
});
}
@override
Future<void> init({bool? isRestore}) async {
cwWalletService ??= xmr_dart.monero
.createMoneroWalletService(DB.instance.moneroWalletInfoBox)
as MoneroWalletService;
if (!(await cwWalletService!.isWalletExist(walletId)) &&
isRestore != true) {
WalletInfo walletInfo;
WalletCredentials credentials;
try {
final dirPath =
await pathForWalletDir(name: walletId, type: WalletType.monero);
final path =
await pathForWallet(name: walletId, type: WalletType.monero);
credentials = xmr_dart.monero.createMoneroNewWalletCredentials(
name: walletId,
language: "English",
);
walletInfo = WalletInfo.external(
id: WalletBase.idFor(walletId, WalletType.monero),
name: walletId,
type: WalletType.monero,
isRecovery: false,
restoreHeight: credentials.height ?? 0,
date: DateTime.now(),
void loadWallet({
required String path,
required String password,
}) {
libMoneroWallet = lib_monero.MoneroWallet.loadWallet(
path: path,
dirPath: dirPath,
address: '',
password: password,
);
credentials.walletInfo = walletInfo;
final _walletCreationService = WalletCreationService(
secureStorage: secureStorageInterface,
walletService: cwWalletService!,
keyService: cwKeysStorage,
type: WalletType.monero,
);
// To restore from a seed
final wallet = await _walletCreationService.create(credentials);
// subtract a couple days to ensure we have a buffer for SWB
final bufferedCreateHeight = xmr_dart.monero.getHeigthByDate(
date: DateTime.now().subtract(const Duration(days: 2)),
);
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;
walletInfo.address = wallet.walletAddresses.address;
await DB.instance
.add<WalletInfo>(boxName: WalletInfo.boxName, value: walletInfo);
wallet.close();
} catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
cwWalletBase?.close();
}
await updateNode();
}
return super.init();
}
@override
Future<void> recover({required bool isRescan}) async {
if (isRescan) {
await refreshMutex.protect(() async {
// clear blockchain info
await mainDB.deleteWalletBlockchainData(walletId);
final restoreHeight = cwWalletBase?.walletInfo.restoreHeight;
highestPercentCached = 0;
await cwWalletBase?.rescan(height: restoreHeight ?? 0);
});
unawaited(refresh());
return;
}
await refreshMutex.protect(() async {
final mnemonic = await getMnemonic();
final seedLength = mnemonic.trim().split(" ").length;
if (seedLength != 25 && seedLength != 16) {
throw Exception("Invalid monero mnemonic length found: $seedLength");
}
try {
final height = max(info.restoreHeight, 0);
await info.updateRestoreHeight(
newRestoreHeight: height,
isar: mainDB.isar,
);
cwWalletService = xmr_dart.monero
.createMoneroWalletService(DB.instance.moneroWalletInfoBox)
as MoneroWalletService;
WalletInfo walletInfo;
WalletCredentials credentials;
final String name = walletId;
final dirPath =
await pathForWalletDir(name: name, type: WalletType.monero);
final path = await pathForWallet(name: name, type: WalletType.monero);
credentials =
xmr_dart.monero.createMoneroRestoreWalletFromSeedCredentials(
name: name,
height: height,
mnemonic: mnemonic.trim(),
);
try {
walletInfo = WalletInfo.external(
id: WalletBase.idFor(name, WalletType.monero),
name: name,
type: WalletType.monero,
isRecovery: false,
restoreHeight: credentials.height ?? 0,
date: DateTime.now(),
Future<lib_monero.Wallet> getCreatedWallet({
required String path,
required String password,
}) async =>
await lib_monero.MoneroWallet.create(
path: path,
dirPath: dirPath,
address: '',
password: password,
seedType: lib_monero.MoneroSeedType
.sixteen, // TODO: check we want to actually use 16 here
);
credentials.walletInfo = walletInfo;
final cwWalletCreationService = WalletCreationService(
secureStorage: secureStorageInterface,
walletService: cwWalletService!,
keyService: cwKeysStorage,
type: WalletType.monero,
);
// To restore from a seed
final wallet =
await cwWalletCreationService.restoreFromSeed(credentials);
walletInfo.address = wallet.walletAddresses.address;
await DB.instance
.add<WalletInfo>(boxName: WalletInfo.boxName, value: walletInfo);
cwWalletBase?.close();
cwWalletBase = wallet as MoneroWalletBase;
cwWalletBase?.onNewBlock = onNewBlock;
cwWalletBase?.onNewTransaction = onNewTransaction;
cwWalletBase?.syncStatusChanged = syncStatusChanged;
if (walletInfo.address != null) {
final newReceivingAddress = await getCurrentReceivingAddress() ??
Address(
walletId: walletId,
derivationIndex: 0,
derivationPath: null,
value: walletInfo.address!,
publicKey: [],
type: AddressType.cryptonote,
subType: AddressSubType.receiving,
);
await mainDB.updateOrPutAddresses([newReceivingAddress]);
await info.updateReceivingAddress(
newAddress: newReceivingAddress.value,
isar: mainDB.isar,
);
}
} catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
}
await updateNode();
await cwWalletBase?.rescan(height: credentials.height);
} catch (e, s) {
Logging.instance.log(
"Exception rethrown from recoverFromMnemonic(): $e\n$s",
level: LogLevel.Error,
);
rethrow;
}
});
}
@override
Future<TxData> prepareSend({required TxData txData}) async {
try {
final feeRate = txData.feeRateType;
if (feeRate is FeeRateType) {
MoneroTransactionPriority feePriority;
switch (feeRate) {
case FeeRateType.fast:
feePriority = MoneroTransactionPriority.fast;
break;
case FeeRateType.average:
feePriority = MoneroTransactionPriority.regular;
break;
case FeeRateType.slow:
feePriority = MoneroTransactionPriority.slow;
break;
default:
throw ArgumentError("Invalid use of custom fee");
}
Future<PendingTransaction>? awaitPendingTransaction;
try {
// check for send all
bool isSendAll = false;
final balance = await availableBalance;
if (txData.amount! == balance &&
txData.recipients!.first.amount == balance) {
isSendAll = true;
}
final List<monero_output.Output> outputs = [];
for (final recipient in txData.recipients!) {
final output = monero_output.Output(cwWalletBase!);
output.address = recipient.address;
output.sendAll = isSendAll;
final String amountToSend = recipient.amount.decimal.toString();
output.setCryptoAmount(amountToSend);
outputs.add(output);
}
final tmp =
xmr_dart.monero.createMoneroTransactionCreationCredentials(
outputs: outputs,
priority: feePriority,
Future<lib_monero.Wallet> getRestoredWallet({
required String path,
required String password,
required String mnemonic,
int height = 0,
}) async =>
await lib_monero.MoneroWallet.restoreWalletFromSeed(
path: path,
password: password,
seed: mnemonic,
restoreHeight: height,
);
final height = await chainHeight;
final inputs = txData.utxos
?.map(
(e) => cw.UTXO(
address: e.address!,
hash: e.txid,
keyImage: e.keyImage!,
value: e.value,
isFrozen: e.isBlocked,
isUnlocked: e.blockHeight != null &&
(height - (e.blockHeight ?? 0)) >=
cryptoCurrency.minConfirms,
height: e.blockHeight ?? 0,
vout: e.vout,
spent: e.used ?? false,
coinbase: e.isCoinbase,
),
)
.toList();
await prepareSendMutex.protect(() async {
awaitPendingTransaction = cwWalletBase!.createTransaction(
tmp,
inputs: inputs,
);
});
} catch (e, s) {
Logging.instance.log(
"Exception rethrown from prepareSend(): $e\n$s",
level: LogLevel.Warning,
);
}
final PendingMoneroTransaction pendingMoneroTransaction =
await (awaitPendingTransaction!) as PendingMoneroTransaction;
final realFee = Amount.fromDecimal(
Decimal.parse(pendingMoneroTransaction.feeFormatted),
fractionDigits: cryptoCurrency.fractionDigits,
);
return txData.copyWith(
fee: realFee,
pendingMoneroTransaction: pendingMoneroTransaction,
);
} else {
throw ArgumentError("Invalid fee rate argument provided!");
}
} catch (e, s) {
Logging.instance.log(
"Exception rethrown from prepare send(): $e\n$s",
level: LogLevel.Info,
);
if (e.toString().contains("Incorrect unlocked balance")) {
throw Exception("Insufficient balance!");
} else if (e is CreationTransactionException) {
throw Exception("Insufficient funds to pay for transaction fee!");
} else {
throw Exception("Transaction failed with error code $e");
}
}
}
@override
Future<TxData> confirmSend({required TxData txData}) async {
try {
try {
await txData.pendingMoneroTransaction!.commit();
Logging.instance.log(
"transaction ${txData.pendingMoneroTransaction!.id} has been sent",
level: LogLevel.Info,
);
return txData.copyWith(txid: txData.pendingMoneroTransaction!.id);
} catch (e, s) {
Logging.instance.log(
"${info.name} monero confirmSend: $e\n$s",
level: LogLevel.Error,
);
rethrow;
}
} catch (e, s) {
Logging.instance.log(
"Exception rethrown from confirmSend(): $e\n$s",
level: LogLevel.Info,
);
rethrow;
void invalidSeedLengthCheck(int length) {
if (length != 25 && length != 16) {
throw Exception("Invalid monero mnemonic length found: $length");
}
}
@override
Future<Amount> get availableBalance async {
try {
int runningBalance = 0;
for (final entry in cwWalletBase!.balance!.entries) {
runningBalance += entry.value.unlockedBalance;
}
return Amount(
rawValue: BigInt.from(runningBalance),
fractionDigits: cryptoCurrency.fractionDigits,
);
} catch (_) {
return info.cachedBalance.spendable;
}
}
@override
Future<Amount> get totalBalance async {
try {
final balanceEntries = cwWalletBase?.balance?.entries;
if (balanceEntries != null) {
int bal = 0;
for (final element in balanceEntries) {
bal = bal + element.value.fullBalance;
}
return Amount(
rawValue: BigInt.from(bal),
fractionDigits: cryptoCurrency.fractionDigits,
);
} else {
final transactions = cwWalletBase!.transactionHistory!.transactions;
int transactionBalance = 0;
for (final tx in transactions!.entries) {
if (tx.value.direction == TransactionDirection.incoming) {
transactionBalance += tx.value.amount!;
} else {
transactionBalance += -tx.value.amount! - tx.value.fee!;
}
}
return Amount(
rawValue: BigInt.from(transactionBalance),
fractionDigits: cryptoCurrency.fractionDigits,
);
}
} catch (_) {
return info.cachedBalance.total;
}
}
// ============== Private ====================================================
StreamSubscription<TorConnectionStatusChangedEvent>? _torStatusListener;
StreamSubscription<TorPreferenceChangedEvent>? _torPreferenceListener;
final Mutex _torConnectingLock = Mutex();
bool _requireMutex = false;
}

View file

@ -1,157 +1,52 @@
import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/utxo.dart' as cw;
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart';
import 'package:cw_wownero/pending_wownero_transaction.dart';
import 'package:cw_wownero/wownero_wallet.dart';
import 'package:cw_wownero/wownero_wallet_service.dart';
import 'package:decimal/decimal.dart';
import 'package:flutter_libmonero/core/wallet_creation_service.dart';
import 'package:flutter_libmonero/view_model/send/output.dart'
as wownero_output;
import 'package:flutter_libmonero/wownero/wownero.dart' as wow_dart;
import 'package:isar/isar.dart';
import 'package:monero/wownero.dart' as wownerodart;
import 'package:mutex/mutex.dart';
import 'package:tuple/tuple.dart';
import 'package:compat/compat.dart' as lib_monero_compat;
import 'package:cs_monero/cs_monero.dart' as lib_monero;
import '../../../db/hive/db.dart';
import '../../../models/isar/models/blockchain_data/address.dart';
import '../../../models/isar/models/blockchain_data/transaction.dart';
import '../../../models/isar/models/blockchain_data/utxo.dart';
import '../../../models/keys/cw_key_data.dart';
import '../../../services/event_bus/events/global/tor_connection_status_changed_event.dart';
import '../../../services/event_bus/events/global/tor_status_changed_event.dart';
import '../../../services/event_bus/global_event_bus.dart';
import '../../../services/tor_service.dart';
import '../../../utilities/amount/amount.dart';
import '../../../utilities/enums/fee_rate_type_enum.dart';
import '../../../utilities/logger.dart';
import '../../crypto_currency/crypto_currency.dart';
import '../../models/tx_data.dart';
import '../intermediate/cryptonote_wallet.dart';
import '../wallet.dart';
import '../wallet_mixin_interfaces/cw_based_interface.dart';
import '../intermediate/lib_monero_wallet.dart';
class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
WowneroWallet(CryptoCurrencyNetwork network) : super(Wownero(network)) {
final bus = GlobalEventBus.instance;
// Listen for tor status changes.
_torStatusListener = bus.on<TorConnectionStatusChangedEvent>().listen(
(event) async {
switch (event.newStatus) {
case TorConnectionStatus.connecting:
if (!_torConnectingLock.isLocked) {
await _torConnectingLock.acquire();
}
_requireMutex = true;
break;
case TorConnectionStatus.connected:
case TorConnectionStatus.disconnected:
if (_torConnectingLock.isLocked) {
_torConnectingLock.release();
}
_requireMutex = false;
break;
}
},
class WowneroWallet extends LibMoneroWallet {
WowneroWallet(CryptoCurrencyNetwork network)
: super(
Wownero(network),
lib_monero_compat.WalletType.wownero,
);
// Listen for tor preference changes.
_torPreferenceListener = bus.on<TorPreferenceChangedEvent>().listen(
(event) async {
await updateNode();
},
);
// Potentially dangerous hack. See comments in _startInit()
_startInit();
}
// cw based wallet listener to handle synchronization of utxo frozen states
late final StreamSubscription<List<UTXO>> _streamSub;
Future<void> _startInit() async {
// Delay required as `mainDB` is not initialized in constructor.
// This is a hack and could lead to a race condition.
Future.delayed(const Duration(seconds: 2), () {
_streamSub = mainDB.isar.utxos
.where()
.walletIdEqualTo(walletId)
.watch(fireImmediately: true)
.listen((utxos) async {
await onUTXOsCHanged(utxos);
await updateBalance(shouldUpdateUtxos: false);
});
});
}
@override
WowneroWalletBase? cwWalletBase;
@override
WowneroWalletService? cwWalletService;
@override
Address addressFor({required int index, int account = 0}) {
final String address = (cwWalletBase as WowneroWalletBase)
.getTransactionAddress(account, index);
final newReceivingAddress = Address(
walletId: walletId,
derivationIndex: index,
derivationPath: null,
value: address,
publicKey: [],
type: AddressType.cryptonote,
subType: AddressSubType.receiving,
);
return newReceivingAddress;
}
@override
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
if (cwWalletBase == null || cwWalletBase?.syncStatus is! SyncedSyncStatus) {
if (libMoneroWallet == null ||
syncStatus is! lib_monero_compat.SyncedSyncStatus) {
return Amount.zeroWith(
fractionDigits: cryptoCurrency.fractionDigits,
);
}
MoneroTransactionPriority priority;
lib_monero.TransactionPriority priority;
FeeRateType feeRateType = FeeRateType.slow;
switch (feeRate) {
case 1:
priority = MoneroTransactionPriority.regular;
priority = lib_monero.TransactionPriority.low;
feeRateType = FeeRateType.average;
break;
case 2:
priority = MoneroTransactionPriority.medium;
priority = lib_monero.TransactionPriority.medium;
feeRateType = FeeRateType.average;
break;
case 3:
priority = MoneroTransactionPriority.fast;
priority = lib_monero.TransactionPriority.high;
feeRateType = FeeRateType.fast;
break;
case 4:
priority = MoneroTransactionPriority.fastest;
priority = lib_monero.TransactionPriority.last;
feeRateType = FeeRateType.fast;
break;
case 0:
default:
priority = MoneroTransactionPriority.slow;
priority = lib_monero.TransactionPriority.normal;
feeRateType = FeeRateType.slow;
break;
}
@ -179,7 +74,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
// unsure why this delay?
await Future<void>.delayed(const Duration(milliseconds: 500));
} catch (e) {
approximateFee = cwWalletBase!.calculateEstimatedFee(
approximateFee = libMoneroWallet!.estimateFee(
priority,
amount.raw.toInt(),
);
@ -198,634 +93,51 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
}
@override
Future<bool> pingCheck() async {
return await cwWalletBase?.isConnected() ?? false;
}
bool walletExists(String path) =>
lib_monero.WowneroWallet.isWalletExist(path);
@override
Future<void> updateNode() async {
final node = getCurrentNode();
final host = Uri.parse(node.host).host;
({InternetAddress host, int port})? proxy;
if (prefs.useTor) {
proxy = TorService.sharedInstance.getProxyInfo();
}
if (_requireMutex) {
await _torConnectingLock.protect(() async {
await cwWalletBase?.connectToNode(
node: Node(
uri: "$host:${node.port}",
type: WalletType.wownero,
trusted: node.trusted ?? false,
useSSL: node.useSSL,
),
socksProxyAddress:
proxy == null ? null : "${proxy.host.address}:${proxy.port}",
);
});
} else {
await cwWalletBase?.connectToNode(
node: Node(
uri: "$host:${node.port}",
type: WalletType.wownero,
trusted: node.trusted ?? false,
useSSL: node.useSSL,
),
socksProxyAddress:
proxy == null ? null : "${proxy.host.address}:${proxy.port}",
);
}
return;
}
@override
Future<CWKeyData?> getKeys() async {
final base = cwWalletBase;
if (base == null || base.walletInfo.name != walletId) {
return null;
}
return CWKeyData(
walletId: walletId,
publicViewKey: base.keys.publicViewKey,
privateViewKey: base.keys.privateViewKey,
publicSpendKey: base.keys.publicSpendKey,
privateSpendKey: base.keys.privateSpendKey,
);
}
@override
Future<void> updateTransactions() async {
final base = cwWalletBase;
if (base == null || base.walletInfo.name != walletId) {
return;
}
await base.updateTransactions();
final transactions = base.transactionHistory?.transactions;
// final cachedTransactions =
// DB.instance.get<dynamic>(boxName: walletId, key: 'latest_tx_model')
// as TransactionData?;
// int latestTxnBlockHeight =
// DB.instance.get<dynamic>(boxName: walletId, key: "storedTxnDataHeight")
// as int? ??
// 0;
//
// final txidsList = DB.instance
// .get<dynamic>(boxName: walletId, key: "cachedTxids") as List? ??
// [];
//
// final Set<String> cachedTxids = Set<String>.from(txidsList);
// TODO: filter to skip cached + confirmed txn processing in next step
// final unconfirmedCachedTransactions =
// cachedTransactions?.getAllTransactions() ?? {};
// unconfirmedCachedTransactions
// .removeWhere((key, value) => value.confirmedStatus);
//
// if (cachedTransactions != null) {
// for (final tx in allTxHashes.toList(growable: false)) {
// final txHeight = tx["height"] as int;
// if (txHeight > 0 &&
// txHeight < latestTxnBlockHeight - MINIMUM_CONFIRMATIONS) {
// if (unconfirmedCachedTransactions[tx["tx_hash"] as String] == null) {
// allTxHashes.remove(tx);
// }
// }
// }
// }
final List<Tuple2<Transaction, Address?>> txnsData = [];
if (transactions != null) {
for (final tx in transactions.entries) {
Address? address;
TransactionType type;
if (tx.value.direction == TransactionDirection.incoming) {
final addressInfo = tx.value.additionalInfo;
final addressString = cwWalletBase?.getTransactionAddress(
addressInfo!['accountIndex'] as int,
addressInfo['addressIndex'] as int,
);
if (addressString != null) {
address = await mainDB
.getAddresses(walletId)
.filter()
.valueEqualTo(addressString)
.findFirst();
}
type = TransactionType.incoming;
} else {
// txn.address = "";
type = TransactionType.outgoing;
}
final txn = Transaction(
walletId: walletId,
txid: tx.value.id,
timestamp: (tx.value.date.millisecondsSinceEpoch ~/ 1000),
type: type,
subType: TransactionSubType.none,
amount: tx.value.amount ?? 0,
amountString: Amount(
rawValue: BigInt.from(tx.value.amount ?? 0),
fractionDigits: cryptoCurrency.fractionDigits,
).toJsonString(),
fee: tx.value.fee ?? 0,
height: tx.value.height,
isCancelled: false,
isLelantus: false,
slateId: null,
otherData: null,
nonce: null,
inputs: [],
outputs: [],
numberOfMessages: null,
);
txnsData.add(Tuple2(txn, address));
}
}
await mainDB.isar.writeTxn(() async {
await mainDB.isar.transactions
.where()
.walletIdEqualTo(walletId)
.deleteAll();
for (final data in txnsData) {
final tx = data.item1;
// save transaction
await mainDB.isar.transactions.put(tx);
if (data.item2 != null) {
final address = await mainDB.getAddress(walletId, data.item2!.value);
// check if address exists in db and add if it does not
if (address == null) {
await mainDB.isar.addresses.put(data.item2!);
}
// link and save address
tx.address.value = address ?? data.item2!;
await tx.address.save();
}
}
});
}
@override
Future<void> init({bool? isRestore}) async {
cwWalletService = wow_dart.wownero
.createWowneroWalletService(DB.instance.moneroWalletInfoBox)
as WowneroWalletService;
if (!(await cwWalletService!.isWalletExist(walletId)) &&
isRestore != true) {
WalletInfo walletInfo;
WalletCredentials credentials;
try {
final dirPath =
await pathForWalletDir(name: walletId, type: WalletType.wownero);
final path =
await pathForWallet(name: walletId, type: WalletType.wownero);
credentials = wow_dart.wownero.createWowneroNewWalletCredentials(
name: walletId,
language: "English",
seedWordsLength: 14,
);
walletInfo = WalletInfo.external(
id: WalletBase.idFor(walletId, WalletType.wownero),
name: walletId,
type: WalletType.wownero,
isRecovery: false,
restoreHeight: credentials.height ?? 0,
date: DateTime.now(),
void loadWallet({
required String path,
required String password,
}) {
libMoneroWallet = lib_monero.WowneroWallet.loadWallet(
path: path,
dirPath: dirPath,
address: '',
);
credentials.walletInfo = walletInfo;
final _walletCreationService = WalletCreationService(
secureStorage: secureStorageInterface,
walletService: cwWalletService!,
keyService: cwKeysStorage,
type: WalletType.wownero,
);
// To restore from a seed
final wallet = await _walletCreationService.create(credentials)
as WowneroWalletBase;
final height =
wownerodart.Wallet_getRefreshFromBlockHeight(wallet.wallet.wptr);
await info.updateRestoreHeight(
newRestoreHeight: height,
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 = height;
walletInfo.address = wallet.walletAddresses.address;
await DB.instance
.add<WalletInfo>(boxName: WalletInfo.boxName, value: walletInfo);
wallet.close();
} catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
cwWalletBase?.close();
}
await updateNode();
}
return super.init();
}
@override
Future<void> open() async {
String? password;
try {
password = await cwKeysStorage.getWalletPassword(walletName: walletId);
} catch (e, s) {
throw Exception("Password not found $e, $s");
}
bool wasNull = false;
if (cwWalletBase == null) {
wasNull = true;
// cwWalletBaseT?.close();
cwWalletBase = (await cwWalletService!.openWallet(walletId, password))
as WowneroWalletBase;
cwWalletBase?.onNewBlock = onNewBlock;
cwWalletBase?.onNewTransaction = onNewTransaction;
cwWalletBase?.syncStatusChanged = syncStatusChanged;
await updateNode();
}
Address? currentAddress = await getCurrentReceivingAddress();
if (currentAddress == null) {
currentAddress = addressFor(index: 0);
await mainDB.updateOrPutAddresses([currentAddress]);
}
if (info.cachedReceivingAddress != currentAddress.value) {
await info.updateReceivingAddress(
newAddress: currentAddress.value,
isar: mainDB.isar,
);
}
if (wasNull) {
await cwWalletBase?.startSync();
} else {
cwWalletBase?.wallet.startListeners();
}
unawaited(refresh());
autoSaveTimer = Timer.periodic(
const Duration(seconds: 193),
(_) async => await cwWalletBase?.save(),
password: password,
);
}
@override
Future<void> recover({required bool isRescan}) async {
if (isRescan) {
await refreshMutex.protect(() async {
// clear blockchain info
await mainDB.deleteWalletBlockchainData(walletId);
final restoreHeight = cwWalletBase?.walletInfo.restoreHeight;
highestPercentCached = 0;
await cwWalletBase?.rescan(height: restoreHeight ?? 0);
});
unawaited(refresh());
return;
}
await refreshMutex.protect(() async {
final mnemonic = await getMnemonic();
final seedLength = mnemonic.trim().split(" ").length;
if (!(seedLength == 14 || seedLength == 25)) {
throw Exception("Invalid wownero mnemonic length found: $seedLength");
}
try {
int height = info.restoreHeight;
// extract seed height from 14 word seed
if (seedLength == 14) {
height = 0;
} else {
height = max(height, 0);
}
await info.updateRestoreHeight(
newRestoreHeight: height,
isar: mainDB.isar,
);
cwWalletService = wow_dart.wownero
.createWowneroWalletService(DB.instance.moneroWalletInfoBox)
as WowneroWalletService;
WalletInfo walletInfo;
WalletCredentials credentials;
final String name = walletId;
final dirPath =
await pathForWalletDir(name: name, type: WalletType.wownero);
final path = await pathForWallet(name: name, type: WalletType.wownero);
credentials =
wow_dart.wownero.createWowneroRestoreWalletFromSeedCredentials(
name: name,
height: height,
mnemonic: mnemonic.trim(),
);
try {
walletInfo = WalletInfo.external(
id: WalletBase.idFor(name, WalletType.wownero),
name: name,
type: WalletType.wownero,
isRecovery: false,
restoreHeight: credentials.height ?? 0,
date: DateTime.now(),
Future<lib_monero.Wallet> getCreatedWallet({
required String path,
required String password,
}) async =>
await lib_monero.WowneroWallet.create(
path: path,
dirPath: dirPath,
// TODO: find out what to put for address
address: '',
password: password,
seedType: lib_monero.WowneroSeedType
.fourteen, // TODO: check we want to actually use 14 here
overrideDeprecated14WordSeedException: true,
);
credentials.walletInfo = walletInfo;
final cwWalletCreationService = WalletCreationService(
secureStorage: secureStorageInterface,
walletService: cwWalletService!,
keyService: cwKeysStorage,
type: WalletType.wownero,
);
// To restore from a seed
final wallet = await cwWalletCreationService
.restoreFromSeed(credentials) as WowneroWalletBase;
height =
wownerodart.Wallet_getRefreshFromBlockHeight(wallet.wallet.wptr);
walletInfo.address = wallet.walletAddresses.address;
walletInfo.restoreHeight = height;
await info.updateRestoreHeight(
newRestoreHeight: height,
isar: mainDB.isar,
);
await DB.instance
.add<WalletInfo>(boxName: WalletInfo.boxName, value: walletInfo);
cwWalletBase?.close();
cwWalletBase = wallet;
cwWalletBase?.onNewBlock = onNewBlock;
cwWalletBase?.onNewTransaction = onNewTransaction;
cwWalletBase?.syncStatusChanged = syncStatusChanged;
if (walletInfo.address != null) {
final newReceivingAddress = await getCurrentReceivingAddress() ??
Address(
walletId: walletId,
derivationIndex: 0,
derivationPath: null,
value: walletInfo.address!,
publicKey: [],
type: AddressType.cryptonote,
subType: AddressSubType.receiving,
);
await mainDB.updateOrPutAddresses([newReceivingAddress]);
await info.updateReceivingAddress(
newAddress: newReceivingAddress.value,
isar: mainDB.isar,
);
}
} catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
}
await updateNode();
await cwWalletBase?.rescan(height: credentials.height);
} catch (e, s) {
Logging.instance.log(
"Exception rethrown from recoverFromMnemonic(): $e\n$s",
level: LogLevel.Error,
);
rethrow;
}
});
}
@override
Future<TxData> prepareSend({required TxData txData}) async {
try {
final feeRate = txData.feeRateType;
if (feeRate is FeeRateType) {
MoneroTransactionPriority feePriority;
switch (feeRate) {
case FeeRateType.fast:
feePriority = MoneroTransactionPriority.fast;
break;
case FeeRateType.average:
feePriority = MoneroTransactionPriority.regular;
break;
case FeeRateType.slow:
feePriority = MoneroTransactionPriority.slow;
break;
default:
throw ArgumentError("Invalid use of custom fee");
}
Future<PendingTransaction>? awaitPendingTransaction;
try {
// check for send all
bool isSendAll = false;
final balance = await availableBalance;
if (txData.amount! == balance &&
txData.recipients!.first.amount == balance) {
isSendAll = true;
}
final List<wownero_output.Output> outputs = [];
for (final recipient in txData.recipients!) {
final output = wownero_output.Output(cwWalletBase!);
output.address = recipient.address;
output.sendAll = isSendAll;
final String amountToSend = recipient.amount.decimal.toString();
output.setCryptoAmount(amountToSend);
outputs.add(output);
}
final tmp =
wow_dart.wownero.createWowneroTransactionCreationCredentials(
outputs: outputs,
priority: feePriority,
Future<lib_monero.Wallet> getRestoredWallet({
required String path,
required String password,
required String mnemonic,
int height = 0,
}) async =>
await lib_monero.WowneroWallet.restoreWalletFromSeed(
path: path,
password: password,
seed: mnemonic,
restoreHeight: height,
);
final height = await chainHeight;
final inputs = txData.utxos
?.map(
(e) => cw.UTXO(
address: e.address!,
hash: e.txid,
keyImage: e.keyImage!,
value: e.value,
isFrozen: e.isBlocked,
isUnlocked: e.blockHeight != null &&
(height - (e.blockHeight ?? 0)) >=
cryptoCurrency.minConfirms,
height: e.blockHeight ?? 0,
vout: e.vout,
spent: e.used ?? false,
coinbase: e.isCoinbase,
),
)
.toList();
await prepareSendMutex.protect(() async {
awaitPendingTransaction = cwWalletBase!.createTransaction(
tmp,
inputs: inputs,
);
});
} catch (e, s) {
Logging.instance.log(
"Exception rethrown from prepareSend(): $e\n$s",
level: LogLevel.Warning,
);
}
final PendingWowneroTransaction pendingWowneroTransaction =
await (awaitPendingTransaction!) as PendingWowneroTransaction;
final realFee = Amount.fromDecimal(
Decimal.parse(pendingWowneroTransaction.feeFormatted),
fractionDigits: cryptoCurrency.fractionDigits,
);
return txData.copyWith(
fee: realFee,
pendingWowneroTransaction: pendingWowneroTransaction,
);
} else {
throw ArgumentError("Invalid fee rate argument provided!");
}
} catch (e, s) {
Logging.instance.log(
"Exception rethrown from prepare send(): $e\n$s",
level: LogLevel.Info,
);
if (e.toString().contains("Incorrect unlocked balance")) {
throw Exception("Insufficient balance!");
} else if (e is CreationTransactionException) {
throw Exception("Insufficient funds to pay for transaction fee!");
} else {
throw Exception("Transaction failed with error code $e");
}
}
}
@override
Future<TxData> confirmSend({required TxData txData}) async {
try {
try {
await txData.pendingWowneroTransaction!.commit();
Logging.instance.log(
"transaction ${txData.pendingWowneroTransaction!.id} has been sent",
level: LogLevel.Info,
);
return txData.copyWith(txid: txData.pendingWowneroTransaction!.id);
} catch (e, s) {
Logging.instance.log(
"${info.name} wownero confirmSend: $e\n$s",
level: LogLevel.Error,
);
rethrow;
}
} catch (e, s) {
Logging.instance.log(
"Exception rethrown from confirmSend(): $e\n$s",
level: LogLevel.Info,
);
rethrow;
void invalidSeedLengthCheck(int length) {
if (!(length == 14 || length == 25)) {
throw Exception("Invalid wownero mnemonic length found: $length");
}
}
@override
Future<Amount> get availableBalance async {
try {
int runningBalance = 0;
for (final entry in cwWalletBase!.balance!.entries) {
runningBalance += entry.value.unlockedBalance;
}
return Amount(
rawValue: BigInt.from(runningBalance),
fractionDigits: cryptoCurrency.fractionDigits,
);
} catch (_) {
return info.cachedBalance.spendable;
}
}
@override
Future<Amount> get totalBalance async {
try {
final balanceEntries = cwWalletBase?.balance?.entries;
if (balanceEntries != null) {
int bal = 0;
for (final element in balanceEntries) {
bal = bal + element.value.fullBalance;
}
return Amount(
rawValue: BigInt.from(bal),
fractionDigits: cryptoCurrency.fractionDigits,
);
} else {
final transactions = cwWalletBase!.transactionHistory!.transactions;
int transactionBalance = 0;
for (final tx in transactions!.entries) {
if (tx.value.direction == TransactionDirection.incoming) {
transactionBalance += tx.value.amount!;
} else {
transactionBalance += -tx.value.amount! - tx.value.fee!;
}
}
return Amount(
rawValue: BigInt.from(transactionBalance),
fractionDigits: cryptoCurrency.fractionDigits,
);
}
} catch (_) {
return info.cachedBalance.total;
}
}
// ============== Private ====================================================
StreamSubscription<TorConnectionStatusChangedEvent>? _torStatusListener;
StreamSubscription<TorPreferenceChangedEvent>? _torPreferenceListener;
final Mutex _torConnectingLock = Mutex();
bool _requireMutex = false;
}

File diff suppressed because it is too large Load diff

View file

@ -1,532 +0,0 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/utxo.dart' as cw;
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter_libmonero/core/key_service.dart';
import 'package:isar/isar.dart';
import 'package:mutex/mutex.dart';
import '../../../models/balance.dart';
import '../../../models/isar/models/blockchain_data/address.dart';
import '../../../models/isar/models/blockchain_data/transaction.dart';
import '../../../models/isar/models/blockchain_data/utxo.dart';
import '../../../models/keys/cw_key_data.dart';
import '../../../models/paymint/fee_object_model.dart';
import '../../../services/event_bus/events/global/blocks_remaining_event.dart';
import '../../../services/event_bus/events/global/refresh_percent_changed_event.dart';
import '../../../services/event_bus/events/global/updated_in_background_event.dart';
import '../../../services/event_bus/events/global/wallet_sync_status_changed_event.dart';
import '../../../services/event_bus/global_event_bus.dart';
import '../../../utilities/amount/amount.dart';
import '../../../utilities/logger.dart';
import '../../../utilities/stack_file_system.dart';
import '../../crypto_currency/intermediate/cryptonote_currency.dart';
import '../../isar/models/wallet_info.dart';
import '../intermediate/cryptonote_wallet.dart';
import 'multi_address_interface.dart';
mixin CwBasedInterface<T extends CryptonoteCurrency, U extends WalletBase,
V extends WalletService> on CryptonoteWallet<T>
implements MultiAddressInterface<T> {
final prepareSendMutex = Mutex();
final estimateFeeMutex = Mutex();
KeyService? _cwKeysStorageCached;
KeyService get cwKeysStorage =>
_cwKeysStorageCached ??= KeyService(secureStorageInterface);
bool _txRefreshLock = false;
int _lastCheckedHeight = -1;
int _txCount = 0;
int currentKnownChainHeight = 0;
double highestPercentCached = 0;
Timer? autoSaveTimer;
Future<String> pathForWalletDir({
required String name,
required WalletType type,
}) async {
final Directory root = await StackFileSystem.applicationRootDirectory();
final prefix = walletTypeToString(type).toLowerCase();
final walletsDir = Directory('${root.path}/wallets');
final walletDire = Directory('${walletsDir.path}/$prefix/$name');
if (!walletDire.existsSync()) {
walletDire.createSync(recursive: true);
}
return walletDire.path;
}
Future<String> pathForWallet({
required String name,
required WalletType type,
}) async =>
await pathForWalletDir(name: name, type: type)
.then((path) => '$path/$name');
void onNewBlock({required int height, required int blocksLeft}) {
currentKnownChainHeight = height;
updateChainHeight();
_refreshTxDataHelper();
}
final _utxosUpdateLock = Mutex();
Future<void> onUTXOsCHanged(List<UTXO> utxos) async {
await _utxosUpdateLock.protect(() async {
final cwUtxos = cwWalletBase?.utxos ?? [];
bool changed = false;
for (final cw in cwUtxos) {
final match = utxos.where(
(e) =>
e.keyImage != null &&
e.keyImage!.isNotEmpty &&
e.keyImage == cw.keyImage,
);
if (match.isNotEmpty) {
final u = match.first;
if (u.isBlocked) {
if (!cw.isFrozen) {
await cwWalletBase?.freeze(cw.keyImage);
changed = true;
}
} else {
if (cw.isFrozen) {
await cwWalletBase?.thaw(cw.keyImage);
changed = true;
}
}
}
}
if (changed) {
await cwWalletBase?.updateUTXOs();
}
});
}
void onNewTransaction() {
// TODO: [prio=low] get rid of UpdatedInBackgroundEvent and move to
// adding the v2 tx to the db which would update ui automagically since the
// db is watched by the ui
// call this here?
GlobalEventBus.instance.fire(
UpdatedInBackgroundEvent(
"New data found in $walletId ${info.name} in background!",
walletId,
),
);
}
void syncStatusChanged() async {
final syncStatus = cwWalletBase?.syncStatus;
if (syncStatus != null) {
if (syncStatus.progress() == 1 && refreshMutex.isLocked) {
refreshMutex.release();
}
WalletSyncStatus? status;
xmrAndWowSyncSpecificFunctionThatShouldBeGottenRidOfInTheFuture(true);
if (syncStatus is SyncingSyncStatus) {
final int blocksLeft = syncStatus.blocksLeft;
// ensure at least 1 to prevent math errors
final int height = max(1, syncStatus.height);
final nodeHeight = height + blocksLeft;
currentKnownChainHeight = nodeHeight;
final percent = height / nodeHeight;
final highest = max(highestPercentCached, percent);
// update cached
if (highestPercentCached < percent) {
highestPercentCached = percent;
}
GlobalEventBus.instance.fire(
RefreshPercentChangedEvent(
highest,
walletId,
),
);
GlobalEventBus.instance.fire(
BlocksRemainingEvent(
blocksLeft,
walletId,
),
);
} else if (syncStatus is SyncedSyncStatus) {
status = WalletSyncStatus.synced;
} else if (syncStatus is NotConnectedSyncStatus) {
status = WalletSyncStatus.unableToSync;
xmrAndWowSyncSpecificFunctionThatShouldBeGottenRidOfInTheFuture(false);
} else if (syncStatus is StartingSyncStatus) {
status = WalletSyncStatus.syncing;
GlobalEventBus.instance.fire(
RefreshPercentChangedEvent(
highestPercentCached,
walletId,
),
);
} else if (syncStatus is FailedSyncStatus) {
status = WalletSyncStatus.unableToSync;
xmrAndWowSyncSpecificFunctionThatShouldBeGottenRidOfInTheFuture(false);
} else if (syncStatus is ConnectingSyncStatus) {
status = WalletSyncStatus.syncing;
GlobalEventBus.instance.fire(
RefreshPercentChangedEvent(
highestPercentCached,
walletId,
),
);
} else if (syncStatus is ConnectedSyncStatus) {
status = WalletSyncStatus.syncing;
GlobalEventBus.instance.fire(
RefreshPercentChangedEvent(
highestPercentCached,
walletId,
),
);
} else if (syncStatus is LostConnectionSyncStatus) {
status = WalletSyncStatus.unableToSync;
xmrAndWowSyncSpecificFunctionThatShouldBeGottenRidOfInTheFuture(false);
}
if (status != null) {
GlobalEventBus.instance.fire(
WalletSyncStatusChangedEvent(
status,
walletId,
info.coin,
),
);
}
}
}
@override
Future<void> checkSaveInitialReceivingAddress() async {
// this doesn't work without opening the wallet first which takes a while
}
// ============ Interface ====================================================
U? get cwWalletBase;
V? get cwWalletService;
Future<Amount> get availableBalance;
Future<Amount> get totalBalance;
Future<void> open();
Address addressFor({required int index, int account = 0});
Future<CWKeyData?> getKeys();
// ============ Private ======================================================
Future<void> _refreshTxDataHelper() async {
if (_txRefreshLock) return;
_txRefreshLock = true;
final syncStatus = cwWalletBase?.syncStatus;
if (syncStatus != null && syncStatus is SyncingSyncStatus) {
final int blocksLeft = syncStatus.blocksLeft;
final tenKChange = blocksLeft ~/ 10000;
// only refresh transactions periodically during a sync
if (_lastCheckedHeight == -1 || tenKChange < _lastCheckedHeight) {
_lastCheckedHeight = tenKChange;
await _refreshTxData();
}
} else {
await _refreshTxData();
}
_txRefreshLock = false;
}
Future<void> _refreshTxData() async {
await updateTransactions();
final count = await mainDB.getTransactions(walletId).count();
if (count > _txCount) {
_txCount = count;
await updateBalance();
GlobalEventBus.instance.fire(
UpdatedInBackgroundEvent(
"New transaction data found in $walletId ${info.name}!",
walletId,
),
);
}
}
// ============ Overrides ====================================================
@override
FilterOperation? get changeAddressFilterOperation => null;
@override
FilterOperation? get receivingAddressFilterOperation => null;
@override
Future<bool> updateUTXOs() async {
await cwWalletBase?.updateUTXOs();
final List<UTXO> outputArray = [];
for (final rawUTXO in (cwWalletBase?.utxos ?? <cw.UTXO>[])) {
if (!rawUTXO.spent) {
final current = await mainDB.isar.utxos
.where()
.walletIdEqualTo(walletId)
.filter()
.voutEqualTo(rawUTXO.vout)
.and()
.txidEqualTo(rawUTXO.hash)
.findFirst();
final tx = await mainDB.isar.transactions
.where()
.walletIdEqualTo(walletId)
.filter()
.txidEqualTo(rawUTXO.hash)
.findFirst();
final otherDataMap = {
"keyImage": rawUTXO.keyImage,
"spent": rawUTXO.spent,
};
final utxo = UTXO(
address: rawUTXO.address,
walletId: walletId,
txid: rawUTXO.hash,
vout: rawUTXO.vout,
value: rawUTXO.value,
name: current?.name ?? "",
isBlocked: current?.isBlocked ?? rawUTXO.isFrozen,
blockedReason: current?.blockedReason ?? "",
isCoinbase: rawUTXO.coinbase,
blockHash: "",
blockHeight:
tx?.height ?? (rawUTXO.height > 0 ? rawUTXO.height : null),
blockTime: tx?.timestamp,
otherData: jsonEncode(otherDataMap),
);
outputArray.add(utxo);
}
}
await mainDB.updateUTXOs(walletId, outputArray);
return true;
}
@override
Future<void> updateBalance({bool shouldUpdateUtxos = true}) async {
if (shouldUpdateUtxos) {
await updateUTXOs();
}
final total = await totalBalance;
final available = await availableBalance;
final balance = Balance(
total: total,
spendable: available,
blockedTotal: Amount(
rawValue: BigInt.zero,
fractionDigits: cryptoCurrency.fractionDigits,
),
pendingSpendable: total - available,
);
await info.updateBalance(newBalance: balance, isar: mainDB.isar);
}
@override
Future<void> refresh() async {
// Awaiting this lock could be dangerous.
// Since refresh is periodic (generally)
if (refreshMutex.isLocked) {
return;
}
// this acquire should be almost instant due to above check.
// Slight possibility of race but should be irrelevant
await refreshMutex.acquire();
GlobalEventBus.instance.fire(
WalletSyncStatusChangedEvent(
WalletSyncStatus.syncing,
walletId,
info.coin,
),
);
await updateTransactions();
await updateBalance();
if (info.otherData[WalletInfoKeys.reuseAddress] != true) {
await checkReceivingAddressForTransactions();
}
if (cwWalletBase?.syncStatus is SyncedSyncStatus) {
refreshMutex.release();
GlobalEventBus.instance.fire(
WalletSyncStatusChangedEvent(
WalletSyncStatus.synced,
walletId,
info.coin,
),
);
}
}
@override
Future<void> exit() async {
autoSaveTimer?.cancel();
await cwWalletBase?.save();
cwWalletBase?.close();
}
@override
Future<void> generateNewReceivingAddress() async {
try {
final currentReceiving = await getCurrentReceivingAddress();
final newReceivingIndex =
currentReceiving == null ? 0 : currentReceiving.derivationIndex + 1;
final newReceivingAddress = addressFor(index: newReceivingIndex);
// Add that new receiving address
await mainDB.putAddress(newReceivingAddress);
await info.updateReceivingAddress(
newAddress: newReceivingAddress.value,
isar: mainDB.isar,
);
} catch (e, s) {
Logging.instance.log(
"Exception in generateNewAddress(): $e\n$s",
level: LogLevel.Error,
);
}
}
@override
Future<void> checkReceivingAddressForTransactions() async {
if (info.otherData[WalletInfoKeys.reuseAddress] == true) {
try {
throw Exception();
} catch (_, s) {
Logging.instance.log(
"checkReceivingAddressForTransactions called but reuse address flag set: $s",
level: LogLevel.Error,
);
}
}
try {
int highestIndex = -1;
final entries = cwWalletBase?.transactionHistory?.transactions?.entries;
if (entries != null) {
for (final element in entries) {
if (element.value.direction == TransactionDirection.incoming) {
final int curAddressIndex =
element.value.additionalInfo!['addressIndex'] as int;
if (curAddressIndex > highestIndex) {
highestIndex = curAddressIndex;
}
}
}
}
// Check the new receiving index
final currentReceiving = await getCurrentReceivingAddress();
final curIndex = currentReceiving?.derivationIndex ?? -1;
if (highestIndex >= curIndex) {
// First increment the receiving index
final newReceivingIndex = curIndex + 1;
// Use new index to derive a new receiving address
final newReceivingAddress = addressFor(index: newReceivingIndex);
final existing = await mainDB
.getAddresses(walletId)
.filter()
.valueEqualTo(newReceivingAddress.value)
.findFirst();
if (existing == null) {
// Add that new change address
await mainDB.putAddress(newReceivingAddress);
} else {
// we need to update the address
await mainDB.updateAddress(existing, newReceivingAddress);
}
if (info.otherData[WalletInfoKeys.reuseAddress] != true) {
// keep checking until address with no tx history is set as current
await checkReceivingAddressForTransactions();
}
}
} on SocketException catch (se, s) {
Logging.instance.log(
"SocketException caught in _checkReceivingAddressForTransactions(): $se\n$s",
level: LogLevel.Error,
);
return;
} catch (e, s) {
Logging.instance.log(
"Exception rethrown from _checkReceivingAddressForTransactions(): $e\n$s",
level: LogLevel.Error,
);
rethrow;
}
}
@override
Future<FeeObject> get fees async => FeeObject(
numberOfBlocksFast: 10,
numberOfBlocksAverage: 15,
numberOfBlocksSlow: 20,
fast: MoneroTransactionPriority.fast.raw!,
medium: MoneroTransactionPriority.regular.raw!,
slow: MoneroTransactionPriority.slow.raw!,
);
@override
Future<void> updateChainHeight() async {
await info.updateCachedChainHeight(
newHeight: currentKnownChainHeight,
isar: mainDB.isar,
);
}
@override
Future<void> checkChangeAddressForTransactions() async {
// do nothing
}
@override
Future<void> generateNewChangeAddress() async {
// do nothing
}
}

View file

@ -1,6 +1,7 @@
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:flutter/material.dart';
import 'package:cs_monero/cs_monero.dart' as lib_monero;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../models/models.dart';
import '../../pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart';
import '../../pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_fee_dropdown.dart';
@ -61,7 +62,7 @@ class _DesktopFeeDialogState extends ConsumerState<DesktopFeeDialog> {
if (coin is Monero || coin is Wownero) {
final fee = await wallet.estimateFeeFor(
amount,
MoneroTransactionPriority.fast.raw!,
lib_monero.TransactionPriority.high.value,
);
ref.read(feeSheetSessionCacheProvider).fast[amount] = fee;
} else if (coin is Firo) {
@ -111,7 +112,7 @@ class _DesktopFeeDialogState extends ConsumerState<DesktopFeeDialog> {
if (coin is Monero || coin is Wownero) {
final fee = await wallet.estimateFeeFor(
amount,
MoneroTransactionPriority.regular.raw!,
lib_monero.TransactionPriority.medium.value,
);
ref.read(feeSheetSessionCacheProvider).average[amount] = fee;
} else if (coin is Firo) {
@ -161,7 +162,7 @@ class _DesktopFeeDialogState extends ConsumerState<DesktopFeeDialog> {
if (coin is Monero || coin is Wownero) {
final fee = await wallet.estimateFeeFor(
amount,
MoneroTransactionPriority.slow.raw!,
lib_monero.TransactionPriority.normal.value,
);
ref.read(feeSheetSessionCacheProvider).slow[amount] = fee;
} else if (coin is Firo) {

View file

@ -27,8 +27,8 @@ import '../utilities/util.dart';
import '../wallets/isar/providers/eth/current_token_wallet_provider.dart';
import '../wallets/wallet/impl/ethereum_wallet.dart';
import '../wallets/wallet/impl/sub_wallets/eth_token_wallet.dart';
import '../wallets/wallet/intermediate/lib_monero_wallet.dart';
import '../wallets/wallet/wallet.dart';
import '../wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
import 'conditional_parent.dart';
import 'desktop/primary_button.dart';
import 'dialogs/basic_dialog.dart';
@ -97,7 +97,7 @@ class SimpleWalletCard extends ConsumerWidget {
if (context.mounted) {
final Future<void> loadFuture;
if (wallet is CwBasedInterface) {
if (wallet is LibMoneroWallet) {
loadFuture = wallet.init().then((value) async => await (wallet).open());
} else {
loadFuture = wallet.init();

View file

@ -6,10 +6,10 @@
#include "generated_plugin_registrant.h"
#include <cs_monero_flutter_libs/cs_monero_flutter_libs_plugin.h>
#include <desktop_drop/desktop_drop_plugin.h>
#include <devicelocale/devicelocale_plugin.h>
#include <flutter_libepiccash/flutter_libepiccash_plugin.h>
#include <flutter_libmonero/flutter_libmonero_plugin.h>
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
@ -18,6 +18,9 @@
#include <window_size/window_size_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) cs_monero_flutter_libs_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "CsMoneroFlutterLibsPlugin");
cs_monero_flutter_libs_plugin_register_with_registrar(cs_monero_flutter_libs_registrar);
g_autoptr(FlPluginRegistrar) desktop_drop_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopDropPlugin");
desktop_drop_plugin_register_with_registrar(desktop_drop_registrar);
@ -27,9 +30,6 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) flutter_libepiccash_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterLibepiccashPlugin");
flutter_libepiccash_plugin_register_with_registrar(flutter_libepiccash_registrar);
g_autoptr(FlPluginRegistrar) flutter_libmonero_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterLibmoneroPlugin");
flutter_libmonero_plugin_register_with_registrar(flutter_libmonero_registrar);
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);

View file

@ -3,10 +3,10 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
cs_monero_flutter_libs
desktop_drop
devicelocale
flutter_libepiccash
flutter_libmonero
flutter_secure_storage_linux
isar_flutter_libs
sqlite3_flutter_libs

View file

@ -7,6 +7,7 @@ import Foundation
import camera_macos
import connectivity_plus
import cs_monero_flutter_libs
import desktop_drop
import device_info_plus
import devicelocale
@ -28,6 +29,7 @@ import window_size
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
CameraMacosPlugin.register(with: registry.registrar(forPlugin: "CameraMacosPlugin"))
ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
CsMoneroFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "CsMoneroFlutterLibsPlugin"))
DesktopDropPlugin.register(with: registry.registrar(forPlugin: "DesktopDropPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin"))

View file

@ -54,14 +54,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.5.0"
asn1lib:
dependency: transitive
description:
name: asn1lib
sha256: "2ca377ad4d677bbadca278e0ba4da4e057b80a10b927bfc8f7d8bda8fe2ceb75"
url: "https://pub.dev"
source: hosted
version: "1.5.4"
async:
dependency: "direct main"
description:
@ -374,6 +366,13 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.18.0"
compat:
dependency: "direct main"
description:
path: "crypto_plugins/cs_monero/compat"
relative: true
source: path
version: "1.0.0"
connectivity_plus:
dependency: "direct main"
description:
@ -430,6 +429,20 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.7.0"
cs_monero:
dependency: "direct main"
description:
path: "crypto_plugins/cs_monero/cs_monero"
relative: true
source: path
version: "1.0.0"
cs_monero_flutter_libs:
dependency: "direct main"
description:
path: "crypto_plugins/cs_monero/cs_monero_flutter_libs"
relative: true
source: path
version: "1.0.0"
csslib:
dependency: transitive
description:
@ -438,27 +451,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.0"
cw_core:
dependency: "direct main"
description:
path: "crypto_plugins/flutter_libmonero/cw_core"
relative: true
source: path
version: "0.0.1"
cw_monero:
dependency: "direct main"
description:
path: "crypto_plugins/flutter_libmonero/cw_monero"
relative: true
source: path
version: "0.0.1"
cw_wownero:
dependency: "direct main"
description:
path: "crypto_plugins/flutter_libmonero/cw_wownero"
relative: true
source: path
version: "0.0.1"
dart_base_x:
dependency: transitive
description:
@ -628,14 +620,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.9.9"
encrypt:
dependency: transitive
description:
name: encrypt
sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
url: "https://pub.dev"
source: hosted
version: "5.0.3"
equatable:
dependency: "direct main"
description:
@ -750,13 +734,6 @@ packages:
relative: true
source: path
version: "0.0.1"
flutter_libmonero:
dependency: "direct main"
description:
path: "crypto_plugins/flutter_libmonero"
relative: true
source: path
version: "0.0.1"
flutter_libsparkmobile:
dependency: "direct main"
description:
@ -798,14 +775,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.2.0"
flutter_mobx:
dependency: transitive
description:
name: flutter_mobx
sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e"
url: "https://pub.dev"
source: hosted
version: "2.2.1+1"
flutter_native_splash:
dependency: "direct main"
description:
@ -1217,6 +1186,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.11"
logger:
dependency: transitive
description:
name: logger
sha256: "697d067c60c20999686a0add96cf6aba723b3aa1f83ecf806a8097231529ec32"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
logging:
dependency: transitive
description:
@ -1281,14 +1258,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.6"
mobx:
dependency: transitive
description:
name: mobx
sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e"
url: "https://pub.dev"
source: hosted
version: "2.3.3+2"
mockingjay:
dependency: "direct dev"
description:
@ -1338,14 +1307,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
nm:
dependency: transitive
description:
@ -1578,14 +1539,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.0"
provider:
dependency: transitive
description:
name: provider
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
url: "https://pub.dev"
source: hosted
version: "6.1.2"
pub_semver:
dependency: transitive
description:

View file

@ -14,7 +14,7 @@ PLUGINS_DIR=../../crypto_plugins
(cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh )
(cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh )
(cd "${PLUGINS_DIR}"/flutter_libmonero/scripts/android/ && ./build_all.sh )
(cd "${PLUGINS_DIR}"/cs_monero/tools/build_scripts && ./build_android.sh )
set_rust_to_1720
(cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh )

View file

@ -14,7 +14,7 @@ PLUGINS_DIR=../../crypto_plugins
(cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh )
(cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh )
(cd "${PLUGINS_DIR}"/flutter_libmonero/scripts/android/ && ./build_all.sh )
(cd "${PLUGINS_DIR}"/cs_monero/tools/build_scripts && ./build_android.sh )
set_rust_to_1720
(cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh )

View file

@ -16,7 +16,7 @@ PLUGINS_DIR=../../crypto_plugins
(cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh )
(cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh )
(cd "${PLUGINS_DIR}"/flutter_libmonero/scripts/android/ && ./build_all.sh )
(cd "${PLUGINS_DIR}"/cs_monero/tools/build_scripts && ./build_android.sh )
set_rust_to_1720
(cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh )

View file

@ -45,14 +45,14 @@ android {
abiFilters "x86_64","armeabi-v7a", "arm64-v8a"
}
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_shared", '-DBUILD_TESTING=OFF', "-DANDROID_TOOLCHAIN=clang -v"
cppFlags "-frtti -fexceptions -v -DANDROID -std=c++17"
// cppFlags "-std=c++11"
version "3.10.2"
}
}
// externalNativeBuild {
// cmake {
// arguments "-DANDROID_STL=c++_shared", '-DBUILD_TESTING=OFF', "-DANDROID_TOOLCHAIN=clang -v"
// cppFlags "-frtti -fexceptions -v -DANDROID -std=c++17"
//// cppFlags "-std=c++11"
// version "3.10.2"
// }
// }
}
signingConfigs {

View file

@ -134,12 +134,6 @@ install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/monero_c/release/monero/x86_64-linux-gnu_libwallet2_api_c.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "monero_libwallet2_api_c.so"
COMPONENT Runtime)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/monero_c/release/wownero/x86_64-linux-gnu_libwallet2_api_c.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "wownero_libwallet2_api_c.so"
COMPONENT Runtime)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libepiccash/scripts/linux/build/rust/target/x86_64-unknown-linux-gnu/release/libepic_cash_wallet.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)

View file

@ -37,17 +37,14 @@ dependencies:
url: https://github.com/cypherstack/flutter_libsparkmobile.git
ref: cc7b43b731e4a7906dd25d4364a08e34554cee19
flutter_libmonero:
path: ./crypto_plugins/flutter_libmonero
cs_monero:
path: ./crypto_plugins/cs_monero/cs_monero
cw_monero:
path: ./crypto_plugins/flutter_libmonero/cw_monero
compat:
path: ./crypto_plugins/cs_monero/compat
cw_wownero:
path: ./crypto_plugins/flutter_libmonero/cw_wownero
cw_core:
path: ./crypto_plugins/flutter_libmonero/cw_core
cs_monero_flutter_libs:
path: ./crypto_plugins/cs_monero/cs_monero_flutter_libs
monero:
git:

View file

@ -86,27 +86,6 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libepiccash
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_liblelantus/scripts/windows/build/libmobileliblelantus.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/monero_c/release/monero/x86_64-w64-mingw32_libwallet2_api_c.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "monero_libwallet2_api_c.dll"
COMPONENT Runtime)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/monero_c/release/wownero/x86_64-w64-mingw32_libwallet2_api_c.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "wownero_libwallet2_api_c.dll"
COMPONENT Runtime)
#install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/monero_c/release/wownero/x86_64-w64-mingw32_libgcc_s_seh-1.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "libgcc_s_seh-1.dll"
# COMPONENT Runtime)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/monero_c/release/wownero/x86_64-w64-mingw32_libpolyseed.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "libpolyseed.dll"
COMPONENT Runtime)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/monero_c/release/wownero/x86_64-w64-mingw32_libssp-0.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "libssp-0.dll"
COMPONENT Runtime)
#install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/monero_c/release/wownero/x86_64-w64-mingw32_libstdc++-6.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "libstdc++-6.dll"
# COMPONENT Runtime)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/monero_c/release/wownero/x86_64-w64-mingw32_libwinpthread-1.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" RENAME "libwinpthread-1.dll"
COMPONENT Runtime)
if(PLUGIN_BUNDLED_LIBRARIES)
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"

View file

@ -16,7 +16,7 @@ rustup target add x86_64-apple-ios
(cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libmonero/scripts/ios/ && ./build_all.sh )
(cd ../../crypto_plugins/cs_monero/tools/build_scripts && ./build_ios.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh )

View file

@ -16,7 +16,7 @@ rustup target add x86_64-apple-ios
(cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libmonero/scripts/ios/ && ./build_all.sh )
(cd ../../crypto_plugins/cs_monero/tools/build_scripts && ./build_ios.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh )

View file

@ -18,7 +18,7 @@ rustup target add x86_64-apple-ios
(cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libmonero/scripts/ios/ && ./build_all.sh )
(cd ../../crypto_plugins/cs_monero/tools/build_scripts && ./build_ios.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh )

View file

@ -14,7 +14,7 @@ mkdir -p build
./build_secure_storage_deps.sh
(cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libmonero/scripts/linux && ./build_all.sh )
(cd ../../crypto_plugins/cs_monero/tools/build_scripts && ./build_linux.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh )

View file

@ -14,7 +14,7 @@ mkdir -p build
./build_secure_storage_deps.sh
(cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libmonero/scripts/linux && ./build_all.sh )
(cd ../../crypto_plugins/cs_monero/tools/build_scripts && ./build_linux.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh )

View file

@ -16,7 +16,7 @@ mkdir -p build
./build_secure_storage_deps.sh &
(cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libmonero/scripts/linux && ./build_all.sh )
(cd ../../crypto_plugins/cs_monero/tools/build_scripts && ./build_linux.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh )

View file

@ -8,7 +8,7 @@ set_rust_to_1671
(cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libmonero/scripts/macos/ && ./build_all.sh )
(cd ../../crypto_plugins/cs_monero/tools/build_scripts && ./build_macos.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh )

View file

@ -8,7 +8,7 @@ set_rust_to_1671
(cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libmonero/scripts/macos/ && ./build_all.sh )
(cd ../../crypto_plugins/cs_monero/tools/build_scripts && ./build_macos.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh )

View file

@ -10,7 +10,7 @@ set_rust_to_1671
(cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libmonero/scripts/macos/ && ./build_all.sh )
(cd ../../crypto_plugins/cs_monero/tools/build_scripts && ./build_macos.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh )

View file

@ -9,7 +9,7 @@ set_rust_to_1671
mkdir -p build
(cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh )
(cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libmonero/scripts/windows && ./build_all.sh)
(cd ../../crypto_plugins/cs_monero/tools/build_scripts && ./build_windows.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh )

View file

@ -9,7 +9,7 @@ set_rust_to_1671
mkdir -p build
(cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh )
(cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libmonero/scripts/windows && ./build_all.sh)
(cd ../../crypto_plugins/cs_monero/tools/build_scripts && ./build_windows.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh )

View file

@ -11,7 +11,7 @@ set_rust_to_1671
mkdir -p build
(cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh )
(cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libmonero/scripts/windows && ./build_all.sh)
(cd ../../crypto_plugins/cs_monero/tools/build_scripts && ./build_windows.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh )

View file

@ -8,6 +8,7 @@
#include <camera_windows/camera_windows.h>
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
#include <cs_monero_flutter_libs/cs_monero_flutter_libs_plugin_c_api.h>
#include <desktop_drop/desktop_drop_plugin.h>
#include <flutter_libepiccash/flutter_libepiccash_plugin_c_api.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
@ -25,6 +26,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("CameraWindows"));
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
CsMoneroFlutterLibsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("CsMoneroFlutterLibsPluginCApi"));
DesktopDropPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("DesktopDropPlugin"));
FlutterLibepiccashPluginCApiRegisterWithRegistrar(

View file

@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
camera_windows
connectivity_plus
cs_monero_flutter_libs
desktop_drop
flutter_libepiccash
flutter_secure_storage_windows