mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-18 16:44:32 +00:00
Merge remote-tracking branch 'origin/staging' into arti
This commit is contained in:
commit
429bd3199b
18 changed files with 602 additions and 280 deletions
|
@ -1 +1 @@
|
||||||
Subproject commit 4b87151d4914606b911f738a8236a6e54a6d8ecb
|
Subproject commit adc7bf50abe4bbe90d5050b82fb5751937cbae4e
|
1
ios/MoneroWallet.framework/.gitignore
vendored
Normal file
1
ios/MoneroWallet.framework/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
MoneroWallet
|
57
ios/MoneroWallet.framework/Info.plist
Normal file
57
ios/MoneroWallet.framework/Info.plist
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<?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>
|
1
ios/WowneroWallet.framework/.gitignore
vendored
Normal file
1
ios/WowneroWallet.framework/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
WowneroWallet
|
57
ios/WowneroWallet.framework/Info.plist
Normal file
57
ios/WowneroWallet.framework/Info.plist
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<?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>
|
|
@ -26,12 +26,20 @@ import '../services/event_bus/events/global/tor_status_changed_event.dart';
|
||||||
import '../services/event_bus/global_event_bus.dart';
|
import '../services/event_bus/global_event_bus.dart';
|
||||||
import '../services/tor_service.dart';
|
import '../services/tor_service.dart';
|
||||||
import '../utilities/amount/amount.dart';
|
import '../utilities/amount/amount.dart';
|
||||||
|
import '../utilities/extensions/impl/string.dart';
|
||||||
import '../utilities/logger.dart';
|
import '../utilities/logger.dart';
|
||||||
import '../utilities/prefs.dart';
|
import '../utilities/prefs.dart';
|
||||||
import '../wallets/crypto_currency/crypto_currency.dart';
|
import '../wallets/crypto_currency/crypto_currency.dart';
|
||||||
import '../wallets/crypto_currency/interfaces/electrumx_currency_interface.dart';
|
import '../wallets/crypto_currency/interfaces/electrumx_currency_interface.dart';
|
||||||
import 'client_manager.dart';
|
import 'client_manager.dart';
|
||||||
|
|
||||||
|
typedef SparkMempoolData = ({
|
||||||
|
String txid,
|
||||||
|
List<String> serialContext,
|
||||||
|
List<String> lTags,
|
||||||
|
List<String> coins,
|
||||||
|
});
|
||||||
|
|
||||||
class WifiOnlyException implements Exception {}
|
class WifiOnlyException implements Exception {}
|
||||||
|
|
||||||
class ElectrumXNode {
|
class ElectrumXNode {
|
||||||
|
@ -1038,10 +1046,9 @@ class ElectrumXClient {
|
||||||
command: "spark.getmempooltxids",
|
command: "spark.getmempooltxids",
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO verify once server is live
|
final txids = List<String>.from(response as List)
|
||||||
final txids = List<String>.from(response as List).toSet();
|
.map((e) => e.toHexReversedFromBase64)
|
||||||
// final map = Map<String, dynamic>.from(response as Map);
|
.toSet();
|
||||||
// final txids = List<String>.from(map["tags"] as List).toSet();
|
|
||||||
|
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Finished ElectrumXClient.getMempoolTxids(). "
|
"Finished ElectrumXClient.getMempoolTxids(). "
|
||||||
|
@ -1057,7 +1064,7 @@ class ElectrumXClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the txids of the current transactions found in the mempool
|
/// Returns the txids of the current transactions found in the mempool
|
||||||
Future<Map<String, dynamic>> getMempoolSparkData({
|
Future<List<SparkMempoolData>> getMempoolSparkData({
|
||||||
String? requestID,
|
String? requestID,
|
||||||
required List<String> txids,
|
required List<String> txids,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -1066,11 +1073,27 @@ class ElectrumXClient {
|
||||||
final response = await request(
|
final response = await request(
|
||||||
requestID: requestID,
|
requestID: requestID,
|
||||||
command: "spark.getmempooltxs",
|
command: "spark.getmempooltxs",
|
||||||
args: txids,
|
args: [
|
||||||
|
{
|
||||||
|
"txids": txids,
|
||||||
|
},
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO verify once server is live
|
|
||||||
final map = Map<String, dynamic>.from(response as Map);
|
final map = Map<String, dynamic>.from(response as Map);
|
||||||
|
final List<SparkMempoolData> result = [];
|
||||||
|
for (final entry in map.entries) {
|
||||||
|
result.add(
|
||||||
|
(
|
||||||
|
txid: entry.key,
|
||||||
|
serialContext:
|
||||||
|
List<String>.from(entry.value["Serial_context"] as List),
|
||||||
|
// the space after lTags is required lol
|
||||||
|
lTags: List<String>.from(entry.value["lTags "] as List),
|
||||||
|
coins: List<String>.from(entry.value["Coins"] as List),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Finished ElectrumXClient.getMempoolSparkData(txids: $txids). "
|
"Finished ElectrumXClient.getMempoolSparkData(txids: $txids). "
|
||||||
|
@ -1078,9 +1101,9 @@ class ElectrumXClient {
|
||||||
level: LogLevel.Info,
|
level: LogLevel.Info,
|
||||||
);
|
);
|
||||||
|
|
||||||
return map;
|
return result;
|
||||||
} catch (e) {
|
} catch (e, s) {
|
||||||
Logging.instance.log(e, level: LogLevel.Error);
|
Logging.instance.log("$e\n$s", level: LogLevel.Error);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,17 +147,15 @@ class _ConfirmChangeNowSendViewState
|
||||||
);
|
);
|
||||||
|
|
||||||
// pop back to wallet
|
// pop back to wallet
|
||||||
if (mounted) {
|
if (context.mounted) {
|
||||||
if (Util.isDesktop) {
|
if (Util.isDesktop) {
|
||||||
|
// pop sending dialog
|
||||||
Navigator.of(context, rootNavigator: true).pop();
|
Navigator.of(context, rootNavigator: true).pop();
|
||||||
|
|
||||||
// stupid hack
|
// one day we'll do routing right
|
||||||
|
Navigator.of(context, rootNavigator: true).pop();
|
||||||
if (widget.fromDesktopStep4) {
|
if (widget.fromDesktopStep4) {
|
||||||
Navigator.of(context, rootNavigator: true).pop();
|
Navigator.of(context, rootNavigator: true).pop();
|
||||||
Navigator.of(context, rootNavigator: true).pop();
|
|
||||||
Navigator.of(context, rootNavigator: true).pop();
|
|
||||||
Navigator.of(context, rootNavigator: true).pop();
|
|
||||||
Navigator.of(context, rootNavigator: true).pop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -285,17 +285,30 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.value == null) {
|
if (response.value == null) {
|
||||||
if (mounted) {
|
if (context.mounted) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
// TODO: better errors
|
||||||
|
String? message;
|
||||||
|
if (response.exception != null) {
|
||||||
|
message =
|
||||||
|
response.exception!.toString();
|
||||||
|
if (message.startsWith(
|
||||||
|
"FormatException:",
|
||||||
|
) &&
|
||||||
|
message.contains("<html>")) {
|
||||||
|
message =
|
||||||
|
"${ref.read(efExchangeProvider).name} server error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unawaited(
|
unawaited(
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
builder: (_) => StackDialog(
|
builder: (_) => StackDialog(
|
||||||
title: "Failed to create trade",
|
title: "Failed to create trade",
|
||||||
message: response.exception
|
message: message ?? "",
|
||||||
?.toString(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -669,7 +669,8 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Expanded(
|
||||||
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
|
@ -679,12 +680,19 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 4,
|
height: 4,
|
||||||
),
|
),
|
||||||
SelectableText(
|
Row(
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: SelectableText(
|
||||||
trade.payInAddress,
|
trade.payInAddress,
|
||||||
style: STextStyles.itemSubtitle12(context),
|
style: STextStyles.itemSubtitle12(context),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
IconCopyButton(
|
IconCopyButton(
|
||||||
data: trade.payInAddress,
|
data: trade.payInAddress,
|
||||||
|
@ -760,10 +768,16 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 4,
|
height: 4,
|
||||||
),
|
),
|
||||||
SelectableText(
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: SelectableText(
|
||||||
trade.payInAddress,
|
trade.payInAddress,
|
||||||
style: STextStyles.itemSubtitle12(context),
|
style: STextStyles.itemSubtitle12(context),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
|
|
|
@ -15,11 +15,9 @@ import 'package:event_bus/event_bus.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import '../../global_settings_view/manage_nodes_views/add_edit_node_view.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
import '../../global_settings_view/tor_settings/tor_settings_view.dart';
|
import 'package:wakelock/wakelock.dart';
|
||||||
import '../../sub_widgets/nodes_list.dart';
|
|
||||||
import 'sub_widgets/confirm_full_rescan.dart';
|
|
||||||
import 'sub_widgets/rescanning_dialog.dart';
|
|
||||||
import '../../../../providers/providers.dart';
|
import '../../../../providers/providers.dart';
|
||||||
import '../../../../route_generator.dart';
|
import '../../../../route_generator.dart';
|
||||||
import '../../../../services/event_bus/events/global/blocks_remaining_event.dart';
|
import '../../../../services/event_bus/events/global/blocks_remaining_event.dart';
|
||||||
|
@ -53,8 +51,11 @@ import '../../../../widgets/rounded_container.dart';
|
||||||
import '../../../../widgets/rounded_white_container.dart';
|
import '../../../../widgets/rounded_white_container.dart';
|
||||||
import '../../../../widgets/stack_dialog.dart';
|
import '../../../../widgets/stack_dialog.dart';
|
||||||
import '../../../../widgets/tor_subscription.dart';
|
import '../../../../widgets/tor_subscription.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import '../../global_settings_view/manage_nodes_views/add_edit_node_view.dart';
|
||||||
import 'package:wakelock/wakelock.dart';
|
import '../../global_settings_view/tor_settings/tor_settings_view.dart';
|
||||||
|
import '../../sub_widgets/nodes_list.dart';
|
||||||
|
import 'sub_widgets/confirm_full_rescan.dart';
|
||||||
|
import 'sub_widgets/rescanning_dialog.dart';
|
||||||
|
|
||||||
/// [eventBus] should only be set during testing
|
/// [eventBus] should only be set during testing
|
||||||
class WalletNetworkSettingsView extends ConsumerStatefulWidget {
|
class WalletNetworkSettingsView extends ConsumerStatefulWidget {
|
||||||
|
|
|
@ -117,13 +117,23 @@ class _StepScaffoldState extends ConsumerState<StepScaffold> {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
String? message;
|
||||||
|
if (response.exception != null) {
|
||||||
|
message = response.exception!.toString();
|
||||||
|
// TODO: better errors
|
||||||
|
if (message.startsWith("FormatException:") &&
|
||||||
|
message.contains("<html>")) {
|
||||||
|
message = "${ref.read(efExchangeProvider).name} server error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unawaited(
|
unawaited(
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
builder: (_) => SimpleDesktopDialog(
|
builder: (_) => SimpleDesktopDialog(
|
||||||
title: "Failed to create trade",
|
title: "Failed to create trade",
|
||||||
message: response.exception?.toString() ?? "",
|
message: message ?? "",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -20,6 +20,7 @@ import '../providers/desktop/current_desktop_menu_item.dart';
|
||||||
import '../themes/stack_colors.dart';
|
import '../themes/stack_colors.dart';
|
||||||
import '../utilities/assets.dart';
|
import '../utilities/assets.dart';
|
||||||
import '../utilities/text_styles.dart';
|
import '../utilities/text_styles.dart';
|
||||||
|
import '../wallets/crypto_currency/crypto_currency.dart';
|
||||||
import '../widgets/desktop/desktop_tor_status_button.dart';
|
import '../widgets/desktop/desktop_tor_status_button.dart';
|
||||||
import '../widgets/desktop/living_stack_icon.dart';
|
import '../widgets/desktop/living_stack_icon.dart';
|
||||||
import 'desktop_menu_item.dart';
|
import 'desktop_menu_item.dart';
|
||||||
|
@ -278,8 +279,14 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
||||||
value: 7,
|
value: 7,
|
||||||
onChanged: (_) {
|
onChanged: (_) {
|
||||||
// todo: save stuff/ notify before exit?
|
// todo: save stuff/ notify before exit?
|
||||||
// exit(0);
|
if (AppConfig.coins
|
||||||
|
.where((e) => e is Monero || e is Wownero)
|
||||||
|
.isNotEmpty) {
|
||||||
|
// hack to insta kill because xmr/wow native lib code sucks
|
||||||
|
exit(0);
|
||||||
|
} else {
|
||||||
SystemNavigator.pop();
|
SystemNavigator.pop();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
controller: controllers[8],
|
controller: controllers[8],
|
||||||
),
|
),
|
||||||
|
|
|
@ -14,6 +14,8 @@ import 'package:event_bus/event_bus.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
import '../../../../pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart';
|
import '../../../../pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart';
|
||||||
import '../../../../providers/providers.dart';
|
import '../../../../providers/providers.dart';
|
||||||
import '../../../../route_generator.dart';
|
import '../../../../route_generator.dart';
|
||||||
|
@ -26,7 +28,6 @@ import '../../../../utilities/text_styles.dart';
|
||||||
import '../../../../utilities/util.dart';
|
import '../../../../utilities/util.dart';
|
||||||
import '../../../../widgets/desktop/desktop_dialog.dart';
|
import '../../../../widgets/desktop/desktop_dialog.dart';
|
||||||
import '../../../../widgets/desktop/desktop_dialog_close_button.dart';
|
import '../../../../widgets/desktop/desktop_dialog_close_button.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
|
||||||
|
|
||||||
class NetworkInfoButton extends ConsumerStatefulWidget {
|
class NetworkInfoButton extends ConsumerStatefulWidget {
|
||||||
const NetworkInfoButton({
|
const NetworkInfoButton({
|
||||||
|
@ -226,7 +227,7 @@ class _NetworkInfoButtonState extends ConsumerState<NetworkInfoButton> {
|
||||||
return [
|
return [
|
||||||
FadePageRoute(
|
FadePageRoute(
|
||||||
DesktopDialog(
|
DesktopDialog(
|
||||||
maxHeight: MediaQuery.of(context).size.height - 64,
|
maxHeight: null,
|
||||||
maxWidth: 580,
|
maxWidth: 580,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
@ -251,19 +252,23 @@ class _NetworkInfoButtonState extends ConsumerState<NetworkInfoButton> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Flexible(
|
||||||
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: 16,
|
top: 16,
|
||||||
left: 32,
|
left: 32,
|
||||||
right: 32,
|
right: 32,
|
||||||
bottom: 32,
|
bottom: 32,
|
||||||
),
|
),
|
||||||
|
child: SingleChildScrollView(
|
||||||
child: WalletNetworkSettingsView(
|
child: WalletNetworkSettingsView(
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
initialSyncStatus: _currentSyncStatus,
|
initialSyncStatus: _currentSyncStatus,
|
||||||
initialNodeStatus: _currentNodeStatus,
|
initialNodeStatus: _currentNodeStatus,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -14,6 +14,7 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
import '../models/isar/models/log.dart';
|
import '../models/isar/models/log.dart';
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
import 'enums/log_level_enum.dart';
|
import 'enums/log_level_enum.dart';
|
||||||
|
@ -30,8 +31,10 @@ class Logging {
|
||||||
static const core.int defaultPrintLength = 1020;
|
static const core.int defaultPrintLength = 1020;
|
||||||
|
|
||||||
late final Isar? isar;
|
late final Isar? isar;
|
||||||
|
late final _AsyncLogWriterQueue _queue;
|
||||||
|
|
||||||
Future<void> init(Isar isar) async {
|
Future<void> init(Isar isar) async {
|
||||||
|
_queue = _AsyncLogWriterQueue();
|
||||||
this.isar = isar;
|
this.isar = isar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +65,11 @@ class Logging {
|
||||||
printFullLength = true;
|
printFullLength = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
isar!.writeTxnSync(() => log.id = isar!.logs.putSync(log));
|
_queue.add(
|
||||||
|
() async => isar!.writeTxn(
|
||||||
|
() async => await isar!.logs.put(log),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
if (printToConsole) {
|
if (printToConsole) {
|
||||||
final core.String logStr = "Log: ${log.toString()}";
|
final core.String logStr = "Log: ${log.toString()}";
|
||||||
|
@ -129,3 +136,33 @@ abstract class Logger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// basic async queue for writing logs in the [Logging] to isar
|
||||||
|
class _AsyncLogWriterQueue {
|
||||||
|
final List<Future<void> Function()> _queue = [];
|
||||||
|
bool _runningLock = false;
|
||||||
|
|
||||||
|
void add(Future<void> Function() futureFunction) {
|
||||||
|
_queue.add(futureFunction);
|
||||||
|
_run();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _run() async {
|
||||||
|
if (_runningLock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_runningLock = true;
|
||||||
|
try {
|
||||||
|
while (_queue.isNotEmpty) {
|
||||||
|
final futureFunction = _queue.removeAt(0);
|
||||||
|
try {
|
||||||
|
await futureFunction.call();
|
||||||
|
} catch (e, s) {
|
||||||
|
debugPrint("$e\n$s");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
_runningLock = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart';
|
import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart';
|
||||||
|
import 'package:cw_wownero/api/account_list.dart';
|
||||||
import 'package:cw_wownero/pending_wownero_transaction.dart';
|
import 'package:cw_wownero/pending_wownero_transaction.dart';
|
||||||
import 'package:cw_wownero/wownero_wallet.dart';
|
import 'package:cw_wownero/wownero_wallet.dart';
|
||||||
import 'package:decimal/decimal.dart';
|
import 'package:decimal/decimal.dart';
|
||||||
|
@ -20,6 +21,7 @@ import 'package:flutter_libmonero/view_model/send/output.dart'
|
||||||
as wownero_output;
|
as wownero_output;
|
||||||
import 'package:flutter_libmonero/wownero/wownero.dart' as wow_dart;
|
import 'package:flutter_libmonero/wownero/wownero.dart' as wow_dart;
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:monero/wownero.dart' as wownerodart;
|
||||||
import 'package:mutex/mutex.dart';
|
import 'package:mutex/mutex.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
|
@ -383,19 +385,11 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
|
||||||
_walletCreationService.type = WalletType.wownero;
|
_walletCreationService.type = WalletType.wownero;
|
||||||
// To restore from a seed
|
// To restore from a seed
|
||||||
final wallet = await _walletCreationService.create(credentials);
|
final wallet = await _walletCreationService.create(credentials);
|
||||||
//
|
|
||||||
// final bufferedCreateHeight = (seedWordsLength == 14)
|
final height = wownerodart.Wallet_getRefreshFromBlockHeight(wptr!);
|
||||||
// ? getSeedHeightSync(wallet?.seed.trim() as String)
|
|
||||||
// : wownero.getHeightByDate(
|
|
||||||
// date: DateTime.now().subtract(const Duration(
|
|
||||||
// days:
|
|
||||||
// 2))); // subtract a couple days to ensure we have a buffer for SWB
|
|
||||||
// TODO(mrcyjanek): implement
|
|
||||||
const bufferedCreateHeight =
|
|
||||||
1; //getSeedHeightSync(wallet!.seed.trim());
|
|
||||||
|
|
||||||
await info.updateRestoreHeight(
|
await info.updateRestoreHeight(
|
||||||
newRestoreHeight: bufferedCreateHeight,
|
newRestoreHeight: height,
|
||||||
isar: mainDB.isar,
|
isar: mainDB.isar,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -410,7 +404,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
|
||||||
value: "",
|
value: "",
|
||||||
);
|
);
|
||||||
|
|
||||||
walletInfo.restoreHeight = bufferedCreateHeight;
|
walletInfo.restoreHeight = height;
|
||||||
|
|
||||||
walletInfo.address = wallet.walletAddresses.address;
|
walletInfo.address = wallet.walletAddresses.address;
|
||||||
await DB.instance
|
await DB.instance
|
||||||
|
@ -515,8 +509,7 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
|
||||||
|
|
||||||
// extract seed height from 14 word seed
|
// extract seed height from 14 word seed
|
||||||
if (seedLength == 14) {
|
if (seedLength == 14) {
|
||||||
// TODO(mrcyjanek): implement
|
height = 0;
|
||||||
height = 1; // getSeedHeightSync(mnemonic.trim());
|
|
||||||
} else {
|
} else {
|
||||||
height = max(height, 0);
|
height = max(height, 0);
|
||||||
}
|
}
|
||||||
|
@ -563,7 +556,13 @@ class WowneroWallet extends CryptonoteWallet with CwBasedInterface {
|
||||||
// To restore from a seed
|
// To restore from a seed
|
||||||
final wallet = await cwWalletCreationService
|
final wallet = await cwWalletCreationService
|
||||||
.restoreFromSeed(credentials) as WowneroWalletBase;
|
.restoreFromSeed(credentials) as WowneroWalletBase;
|
||||||
|
height = wownerodart.Wallet_getRefreshFromBlockHeight(wptr!);
|
||||||
walletInfo.address = wallet.walletAddresses.address;
|
walletInfo.address = wallet.walletAddresses.address;
|
||||||
|
walletInfo.restoreHeight = height;
|
||||||
|
await info.updateRestoreHeight(
|
||||||
|
newRestoreHeight: height,
|
||||||
|
isar: mainDB.isar,
|
||||||
|
);
|
||||||
await DB.instance
|
await DB.instance
|
||||||
.add<WalletInfo>(boxName: WalletInfo.boxName, value: walletInfo);
|
.add<WalletInfo>(boxName: WalletInfo.boxName, value: walletInfo);
|
||||||
CwBasedInterface.cwWalletBase?.close();
|
CwBasedInterface.cwWalletBase?.close();
|
||||||
|
|
|
@ -635,7 +635,9 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
|
||||||
// been marked as isUsed.
|
// been marked as isUsed.
|
||||||
// TODO: [prio=med] Could (probably should) throw an exception here if txData.usedSparkCoins is null or empty
|
// TODO: [prio=med] Could (probably should) throw an exception here if txData.usedSparkCoins is null or empty
|
||||||
if (txData.usedSparkCoins != null && txData.usedSparkCoins!.isNotEmpty) {
|
if (txData.usedSparkCoins != null && txData.usedSparkCoins!.isNotEmpty) {
|
||||||
await _addOrUpdateSparkCoins(txData.usedSparkCoins!);
|
await mainDB.isar.writeTxn(() async {
|
||||||
|
await mainDB.isar.sparkCoins.putAll(txData.usedSparkCoins!);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return await updateSentCachedTxData(txData: txData);
|
return await updateSentCachedTxData(txData: txData);
|
||||||
|
@ -648,7 +650,88 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// in mem cache
|
||||||
|
Set<String> _mempoolTxids = {};
|
||||||
|
Set<String> _mempoolTxidsChecked = {};
|
||||||
|
|
||||||
|
Future<List<SparkCoin>> _refreshSparkCoinsMempoolCheck({
|
||||||
|
required Set<String> privateKeyHexSet,
|
||||||
|
required int groupId,
|
||||||
|
}) async {
|
||||||
|
final start = DateTime.now();
|
||||||
|
try {
|
||||||
|
// update cache
|
||||||
|
_mempoolTxids = await electrumXClient.getMempoolTxids();
|
||||||
|
|
||||||
|
// remove any checked txids that are not in the mempool anymore
|
||||||
|
_mempoolTxidsChecked = _mempoolTxidsChecked.intersection(_mempoolTxids);
|
||||||
|
|
||||||
|
// get all unchecked txids currently in mempool
|
||||||
|
final txidsToCheck = _mempoolTxids.difference(_mempoolTxidsChecked);
|
||||||
|
if (txidsToCheck.isEmpty) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch spark data to scan if we own any unconfirmed spark coins
|
||||||
|
final sparkDataToCheck = await electrumXClient.getMempoolSparkData(
|
||||||
|
txids: txidsToCheck.toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
final Set<String> checkedTxids = {};
|
||||||
|
final List<List<String>> rawCoins = [];
|
||||||
|
|
||||||
|
for (final data in sparkDataToCheck) {
|
||||||
|
for (int i = 0; i < data.coins.length; i++) {
|
||||||
|
rawCoins.add([
|
||||||
|
data.coins[i],
|
||||||
|
data.txid,
|
||||||
|
data.serialContext.first,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkedTxids.add(data.txid);
|
||||||
|
}
|
||||||
|
|
||||||
|
final result = <SparkCoin>[];
|
||||||
|
|
||||||
|
// if there is new data we try and identify the coins
|
||||||
|
if (rawCoins.isNotEmpty) {
|
||||||
|
// run identify off main isolate
|
||||||
|
final myCoins = await compute(
|
||||||
|
_identifyCoins,
|
||||||
|
(
|
||||||
|
anonymitySetCoins: rawCoins,
|
||||||
|
groupId: groupId,
|
||||||
|
privateKeyHexSet: privateKeyHexSet,
|
||||||
|
walletId: walletId,
|
||||||
|
isTestNet: cryptoCurrency.network == CryptoCurrencyNetwork.test,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// add checked txids after identification
|
||||||
|
_mempoolTxidsChecked.addAll(checkedTxids);
|
||||||
|
|
||||||
|
result.addAll(myCoins);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (e) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"refreshSparkMempoolData() failed: $e",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
return [];
|
||||||
|
} finally {
|
||||||
|
Logging.instance.log(
|
||||||
|
"$walletId ${info.name} refreshSparkCoinsMempoolCheck() run "
|
||||||
|
"duration: ${DateTime.now().difference(start)}",
|
||||||
|
level: LogLevel.Debug,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> refreshSparkData() async {
|
Future<void> refreshSparkData() async {
|
||||||
|
final start = DateTime.now();
|
||||||
try {
|
try {
|
||||||
// start by checking if any previous sets are missing from db and add the
|
// start by checking if any previous sets are missing from db and add the
|
||||||
// missing groupIds to the list if sets to check and update
|
// missing groupIds to the list if sets to check and update
|
||||||
|
@ -684,46 +767,158 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await _checkAndUpdateCoins();
|
// Get cached timestamps per groupId. These timestamps are used to check
|
||||||
// refresh spark balance
|
// and try to id coins that were added to the spark anon set cache
|
||||||
await refreshSparkBalance();
|
// after that timestamp.
|
||||||
} catch (e, s) {
|
final groupIdTimestampUTCMap =
|
||||||
Logging.instance.log(
|
info.otherData[WalletInfoKeys.firoSparkCacheSetTimestampCache]
|
||||||
"$runtimeType $walletId ${info.name}: $e\n$s",
|
as Map? ??
|
||||||
level: LogLevel.Error,
|
{};
|
||||||
|
|
||||||
|
// iterate through the cache, fetching spark coin data that hasn't been
|
||||||
|
// processed by this wallet yet
|
||||||
|
final Map<int, List<List<String>>> rawCoinsBySetId = {};
|
||||||
|
for (int i = 1; i <= latestGroupId; i++) {
|
||||||
|
final lastCheckedTimeStampUTC =
|
||||||
|
groupIdTimestampUTCMap[i.toString()] as int? ?? 0;
|
||||||
|
final info = await FiroCacheCoordinator.getLatestSetInfoForGroupId(
|
||||||
|
i,
|
||||||
);
|
);
|
||||||
rethrow;
|
final anonymitySetResult =
|
||||||
}
|
await FiroCacheCoordinator.getSetCoinsForGroupId(
|
||||||
|
i,
|
||||||
|
newerThanTimeStamp: lastCheckedTimeStampUTC,
|
||||||
|
);
|
||||||
|
final coinsRaw = anonymitySetResult
|
||||||
|
.map(
|
||||||
|
(e) => [
|
||||||
|
e.serialized,
|
||||||
|
e.txHash,
|
||||||
|
e.context,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (coinsRaw.isNotEmpty) {
|
||||||
|
rawCoinsBySetId[i] = coinsRaw;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Set<LTagPair>> getMissingSparkSpendTransactionIds() async {
|
// update last checked timestamp data
|
||||||
final tags = await mainDB.isar.sparkCoins
|
groupIdTimestampUTCMap[i.toString()] = max(
|
||||||
.where()
|
lastCheckedTimeStampUTC,
|
||||||
.walletIdEqualToAnyLTagHash(walletId)
|
info?.timestampUTC ?? lastCheckedTimeStampUTC,
|
||||||
.filter()
|
);
|
||||||
.isUsedEqualTo(true)
|
}
|
||||||
.lTagHashProperty()
|
|
||||||
.findAll();
|
|
||||||
|
|
||||||
final usedCoinTxidsFoundLocally = await mainDB.isar.transactionV2s
|
// get address(es) to get the private key hex strings required for
|
||||||
|
// identifying spark coins
|
||||||
|
final sparkAddresses = await mainDB.isar.addresses
|
||||||
.where()
|
.where()
|
||||||
.walletIdEqualTo(walletId)
|
.walletIdEqualTo(walletId)
|
||||||
.filter()
|
.filter()
|
||||||
.subTypeEqualTo(TransactionSubType.sparkSpend)
|
.typeEqualTo(AddressType.spark)
|
||||||
.txidProperty()
|
|
||||||
.findAll();
|
.findAll();
|
||||||
|
final root = await getRootHDNode();
|
||||||
|
final Set<String> privateKeyHexSet = sparkAddresses
|
||||||
|
.map(
|
||||||
|
(e) =>
|
||||||
|
root.derivePath(e.derivationPath!.value).privateKey.data.toHex,
|
||||||
|
)
|
||||||
|
.toSet();
|
||||||
|
|
||||||
final pairs = await FiroCacheCoordinator.getUsedCoinTxidsFor(
|
// try to identify any coins in the unchecked set data
|
||||||
tags: tags,
|
final List<SparkCoin> newlyIdCoins = [];
|
||||||
|
for (final groupId in rawCoinsBySetId.keys) {
|
||||||
|
final myCoins = await compute(
|
||||||
|
_identifyCoins,
|
||||||
|
(
|
||||||
|
anonymitySetCoins: rawCoinsBySetId[groupId]!,
|
||||||
|
groupId: groupId,
|
||||||
|
privateKeyHexSet: privateKeyHexSet,
|
||||||
|
walletId: walletId,
|
||||||
|
isTestNet: cryptoCurrency.network == CryptoCurrencyNetwork.test,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
newlyIdCoins.addAll(myCoins);
|
||||||
pairs.removeWhere((e) => usedCoinTxidsFoundLocally.contains(e.txid));
|
}
|
||||||
|
// if any were found, add to database
|
||||||
return pairs.toSet();
|
if (newlyIdCoins.isNotEmpty) {
|
||||||
|
await mainDB.isar.writeTxn(() async {
|
||||||
|
await mainDB.isar.sparkCoins.putAll(newlyIdCoins);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> refreshSparkBalance() async {
|
// finally update the cached timestamps in the database
|
||||||
|
await info.updateOtherData(
|
||||||
|
newEntries: {
|
||||||
|
WalletInfoKeys.firoSparkCacheSetTimestampCache:
|
||||||
|
groupIdTimestampUTCMap,
|
||||||
|
},
|
||||||
|
isar: mainDB.isar,
|
||||||
|
);
|
||||||
|
|
||||||
|
// check for spark coins in mempool
|
||||||
|
final mempoolMyCoins = await _refreshSparkCoinsMempoolCheck(
|
||||||
|
privateKeyHexSet: privateKeyHexSet,
|
||||||
|
groupId: latestGroupId,
|
||||||
|
);
|
||||||
|
// if any were found, add to database
|
||||||
|
if (mempoolMyCoins.isNotEmpty) {
|
||||||
|
await mainDB.isar.writeTxn(() async {
|
||||||
|
await mainDB.isar.sparkCoins.putAll(mempoolMyCoins);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// get unused and or unconfirmed coins from db
|
||||||
|
final coinsToCheck = await mainDB.isar.sparkCoins
|
||||||
|
.where()
|
||||||
|
.walletIdEqualToAnyLTagHash(walletId)
|
||||||
|
.filter()
|
||||||
|
.heightIsNull()
|
||||||
|
.or()
|
||||||
|
.isUsedEqualTo(false)
|
||||||
|
.findAll();
|
||||||
|
|
||||||
|
Set<String>? spentCoinTags;
|
||||||
|
// only fetch tags from db if we need them to compare against any items
|
||||||
|
// in coinsToCheck
|
||||||
|
if (coinsToCheck.isNotEmpty) {
|
||||||
|
spentCoinTags = await FiroCacheCoordinator.getUsedCoinTags(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check and update coins if required
|
||||||
|
final List<SparkCoin> updatedCoins = [];
|
||||||
|
for (final coin in coinsToCheck) {
|
||||||
|
SparkCoin updated = coin;
|
||||||
|
|
||||||
|
if (updated.height == null) {
|
||||||
|
final tx = await electrumXCachedClient.getTransaction(
|
||||||
|
txHash: updated.txHash,
|
||||||
|
cryptoCurrency: info.coin,
|
||||||
|
);
|
||||||
|
if (tx["height"] is int) {
|
||||||
|
updated = updated.copyWith(height: tx["height"] as int);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updated.height != null &&
|
||||||
|
spentCoinTags!.contains(updated.lTagHash)) {
|
||||||
|
updated = coin.copyWith(isUsed: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedCoins.add(updated);
|
||||||
|
}
|
||||||
|
// update in db if any have changed
|
||||||
|
if (updatedCoins.isNotEmpty) {
|
||||||
|
await mainDB.isar.writeTxn(() async {
|
||||||
|
await mainDB.isar.sparkCoins.putAll(updatedCoins);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// used to check if balance is spendable or total
|
||||||
final currentHeight = await chainHeight;
|
final currentHeight = await chainHeight;
|
||||||
|
|
||||||
|
// get all unused coins to update wallet spark balance
|
||||||
final unusedCoins = await mainDB.isar.sparkCoins
|
final unusedCoins = await mainDB.isar.sparkCoins
|
||||||
.where()
|
.where()
|
||||||
.walletIdEqualToAnyLTagHash(walletId)
|
.walletIdEqualToAnyLTagHash(walletId)
|
||||||
|
@ -759,10 +954,50 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
|
||||||
pendingSpendable: total - spendable,
|
pendingSpendable: total - spendable,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// finally update balance in db
|
||||||
await info.updateBalanceTertiary(
|
await info.updateBalanceTertiary(
|
||||||
newBalance: sparkBalance,
|
newBalance: sparkBalance,
|
||||||
isar: mainDB.isar,
|
isar: mainDB.isar,
|
||||||
);
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"$runtimeType $walletId ${info.name}: $e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
rethrow;
|
||||||
|
} finally {
|
||||||
|
Logging.instance.log(
|
||||||
|
"${info.name} refreshSparkData() duration:"
|
||||||
|
" ${DateTime.now().difference(start)}",
|
||||||
|
level: LogLevel.Debug,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Set<LTagPair>> getMissingSparkSpendTransactionIds() async {
|
||||||
|
final tags = await mainDB.isar.sparkCoins
|
||||||
|
.where()
|
||||||
|
.walletIdEqualToAnyLTagHash(walletId)
|
||||||
|
.filter()
|
||||||
|
.isUsedEqualTo(true)
|
||||||
|
.lTagHashProperty()
|
||||||
|
.findAll();
|
||||||
|
|
||||||
|
final usedCoinTxidsFoundLocally = await mainDB.isar.transactionV2s
|
||||||
|
.where()
|
||||||
|
.walletIdEqualTo(walletId)
|
||||||
|
.filter()
|
||||||
|
.subTypeEqualTo(TransactionSubType.sparkSpend)
|
||||||
|
.txidProperty()
|
||||||
|
.findAll();
|
||||||
|
|
||||||
|
final pairs = await FiroCacheCoordinator.getUsedCoinTxidsFor(
|
||||||
|
tags: tags,
|
||||||
|
);
|
||||||
|
|
||||||
|
pairs.removeWhere((e) => usedCoinTxidsFoundLocally.contains(e.txid));
|
||||||
|
|
||||||
|
return pairs.toSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Should only be called within the standard wallet [recover] function due to
|
/// Should only be called within the standard wallet [recover] function due to
|
||||||
|
@ -777,10 +1012,7 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await _checkAndUpdateCoins();
|
await refreshSparkData();
|
||||||
|
|
||||||
// refresh spark balance
|
|
||||||
await refreshSparkBalance();
|
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"$runtimeType $walletId ${info.name}: $e\n$s",
|
"$runtimeType $walletId ${info.name}: $e\n$s",
|
||||||
|
@ -790,115 +1022,6 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _checkAndUpdateCoins() async {
|
|
||||||
final sparkAddresses = await mainDB.isar.addresses
|
|
||||||
.where()
|
|
||||||
.walletIdEqualTo(walletId)
|
|
||||||
.filter()
|
|
||||||
.typeEqualTo(AddressType.spark)
|
|
||||||
.findAll();
|
|
||||||
final root = await getRootHDNode();
|
|
||||||
final Set<String> privateKeyHexSet = sparkAddresses
|
|
||||||
.map(
|
|
||||||
(e) => root.derivePath(e.derivationPath!.value).privateKey.data.toHex,
|
|
||||||
)
|
|
||||||
.toSet();
|
|
||||||
|
|
||||||
final Map<int, List<List<String>>> rawCoinsBySetId = {};
|
|
||||||
|
|
||||||
final groupIdTimestampUTCMap =
|
|
||||||
info.otherData[WalletInfoKeys.firoSparkCacheSetTimestampCache]
|
|
||||||
as Map? ??
|
|
||||||
{};
|
|
||||||
|
|
||||||
final latestSparkCoinId = await electrumXClient.getSparkLatestCoinId();
|
|
||||||
for (int i = 1; i <= latestSparkCoinId; i++) {
|
|
||||||
final lastCheckedTimeStampUTC =
|
|
||||||
groupIdTimestampUTCMap[i.toString()] as int? ?? 0;
|
|
||||||
final info = await FiroCacheCoordinator.getLatestSetInfoForGroupId(
|
|
||||||
i,
|
|
||||||
);
|
|
||||||
final anonymitySetResult =
|
|
||||||
await FiroCacheCoordinator.getSetCoinsForGroupId(
|
|
||||||
i,
|
|
||||||
newerThanTimeStamp: lastCheckedTimeStampUTC,
|
|
||||||
);
|
|
||||||
final coinsRaw = anonymitySetResult
|
|
||||||
.map(
|
|
||||||
(e) => [
|
|
||||||
e.serialized,
|
|
||||||
e.txHash,
|
|
||||||
e.context,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (coinsRaw.isNotEmpty) {
|
|
||||||
rawCoinsBySetId[i] = coinsRaw;
|
|
||||||
}
|
|
||||||
|
|
||||||
groupIdTimestampUTCMap[i.toString()] = max(
|
|
||||||
lastCheckedTimeStampUTC,
|
|
||||||
info?.timestampUTC ?? lastCheckedTimeStampUTC,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await info.updateOtherData(
|
|
||||||
newEntries: {
|
|
||||||
WalletInfoKeys.firoSparkCacheSetTimestampCache: groupIdTimestampUTCMap,
|
|
||||||
},
|
|
||||||
isar: mainDB.isar,
|
|
||||||
);
|
|
||||||
|
|
||||||
final List<SparkCoin> newlyIdCoins = [];
|
|
||||||
for (final groupId in rawCoinsBySetId.keys) {
|
|
||||||
final myCoins = await compute(
|
|
||||||
_identifyCoins,
|
|
||||||
(
|
|
||||||
anonymitySetCoins: rawCoinsBySetId[groupId]!,
|
|
||||||
groupId: groupId,
|
|
||||||
privateKeyHexSet: privateKeyHexSet,
|
|
||||||
walletId: walletId,
|
|
||||||
isTestNet: cryptoCurrency.network == CryptoCurrencyNetwork.test,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
newlyIdCoins.addAll(myCoins);
|
|
||||||
}
|
|
||||||
|
|
||||||
await _checkAndMarkCoinsUsedInDB(coinsNotInDbYet: newlyIdCoins);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _checkAndMarkCoinsUsedInDB({
|
|
||||||
List<SparkCoin> coinsNotInDbYet = const [],
|
|
||||||
}) async {
|
|
||||||
final List<SparkCoin> coins = await mainDB.isar.sparkCoins
|
|
||||||
.where()
|
|
||||||
.walletIdEqualToAnyLTagHash(walletId)
|
|
||||||
.filter()
|
|
||||||
.isUsedEqualTo(false)
|
|
||||||
.findAll();
|
|
||||||
|
|
||||||
final List<SparkCoin> coinsToWrite = [];
|
|
||||||
|
|
||||||
final spentCoinTags = await FiroCacheCoordinator.getUsedCoinTags(0);
|
|
||||||
|
|
||||||
for (final coin in coins) {
|
|
||||||
if (spentCoinTags.contains(coin.lTagHash)) {
|
|
||||||
coinsToWrite.add(coin.copyWith(isUsed: true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (final coin in coinsNotInDbYet) {
|
|
||||||
if (spentCoinTags.contains(coin.lTagHash)) {
|
|
||||||
coinsToWrite.add(coin.copyWith(isUsed: true));
|
|
||||||
} else {
|
|
||||||
coinsToWrite.add(coin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update wallet spark coins in isar
|
|
||||||
await _addOrUpdateSparkCoins(coinsToWrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
// modelled on CSparkWallet::CreateSparkMintTransactions https://github.com/firoorg/firo/blob/39c41e5e7ec634ced3700fe3f4f5509dc2e480d0/src/spark/sparkwallet.cpp#L752
|
// modelled on CSparkWallet::CreateSparkMintTransactions https://github.com/firoorg/firo/blob/39c41e5e7ec634ced3700fe3f4f5509dc2e480d0/src/spark/sparkwallet.cpp#L752
|
||||||
Future<List<TxData>> _createSparkMintTransactions({
|
Future<List<TxData>> _createSparkMintTransactions({
|
||||||
required List<UTXO> availableUtxos,
|
required List<UTXO> availableUtxos,
|
||||||
|
@ -1698,37 +1821,6 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
|
||||||
|
|
||||||
// ====================== Private ============================================
|
// ====================== Private ============================================
|
||||||
|
|
||||||
Future<void> _addOrUpdateSparkCoins(List<SparkCoin> coins) async {
|
|
||||||
if (coins.isNotEmpty) {
|
|
||||||
await mainDB.isar.writeTxn(() async {
|
|
||||||
await mainDB.isar.sparkCoins.putAll(coins);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// update wallet spark coin height
|
|
||||||
final coinsToCheck = await mainDB.isar.sparkCoins
|
|
||||||
.where()
|
|
||||||
.walletIdEqualToAnyLTagHash(walletId)
|
|
||||||
.filter()
|
|
||||||
.heightIsNull()
|
|
||||||
.findAll();
|
|
||||||
final List<SparkCoin> updatedCoins = [];
|
|
||||||
for (final coin in coinsToCheck) {
|
|
||||||
final tx = await electrumXCachedClient.getTransaction(
|
|
||||||
txHash: coin.txHash,
|
|
||||||
cryptoCurrency: info.coin,
|
|
||||||
);
|
|
||||||
if (tx["height"] is int) {
|
|
||||||
updatedCoins.add(coin.copyWith(height: tx["height"] as int));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (updatedCoins.isNotEmpty) {
|
|
||||||
await mainDB.isar.writeTxn(() async {
|
|
||||||
await mainDB.isar.sparkCoins.putAll(updatedCoins);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
btc.NetworkType get _bitcoinDartNetwork => btc.NetworkType(
|
btc.NetworkType get _bitcoinDartNetwork => btc.NetworkType(
|
||||||
messagePrefix: cryptoCurrency.networkParams.messagePrefix,
|
messagePrefix: cryptoCurrency.networkParams.messagePrefix,
|
||||||
bech32: cryptoCurrency.networkParams.bech32Hrp,
|
bech32: cryptoCurrency.networkParams.bech32Hrp,
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
B49D91439948369648AB0603 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51604430FD0FD1FA5C4767A0 /* Pods_Runner.framework */; };
|
B49D91439948369648AB0603 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51604430FD0FD1FA5C4767A0 /* Pods_Runner.framework */; };
|
||||||
CE6B5DF12BF26AAA00CF1F44 /* monero_libwallet2_api_c.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE6B5DEF2BF26AAA00CF1F44 /* monero_libwallet2_api_c.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
CEFE41202C20387E00086DB4 /* WowneroWallet.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE4F88332C202CF4007A8C67 /* WowneroWallet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
CE6B5DF22BF26AAA00CF1F44 /* wownero_libwallet2_api_c.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE6B5DF02BF26AAA00CF1F44 /* wownero_libwallet2_api_c.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
CEFE41212C20387E00086DB4 /* MoneroWallet.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE4F88302C202CEE007A8C67 /* MoneroWallet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
@ -40,8 +40,8 @@
|
||||||
dstPath = "";
|
dstPath = "";
|
||||||
dstSubfolderSpec = 10;
|
dstSubfolderSpec = 10;
|
||||||
files = (
|
files = (
|
||||||
CE6B5DF12BF26AAA00CF1F44 /* monero_libwallet2_api_c.dylib in CopyFiles */,
|
CEFE41202C20387E00086DB4 /* WowneroWallet.framework in CopyFiles */,
|
||||||
CE6B5DF22BF26AAA00CF1F44 /* wownero_libwallet2_api_c.dylib in CopyFiles */,
|
CEFE41212C20387E00086DB4 /* MoneroWallet.framework in CopyFiles */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -75,8 +75,8 @@
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
B999088F2ABE1E170012A442 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
B999088F2ABE1E170012A442 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||||
CE6B5DEF2BF26AAA00CF1F44 /* monero_libwallet2_api_c.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = monero_libwallet2_api_c.dylib; sourceTree = "<group>"; };
|
CE4F88302C202CEE007A8C67 /* MoneroWallet.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MoneroWallet.framework; sourceTree = "<group>"; };
|
||||||
CE6B5DF02BF26AAA00CF1F44 /* wownero_libwallet2_api_c.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = wownero_libwallet2_api_c.dylib; sourceTree = "<group>"; };
|
CE4F88332C202CF4007A8C67 /* WowneroWallet.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = WowneroWallet.framework; sourceTree = "<group>"; };
|
||||||
E6F536731AC506735EB76340 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
E6F536731AC506735EB76340 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
@ -137,8 +137,8 @@
|
||||||
97C146E51CF9000F007C117D = {
|
97C146E51CF9000F007C117D = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
CE6B5DEF2BF26AAA00CF1F44 /* monero_libwallet2_api_c.dylib */,
|
CE4F88332C202CF4007A8C67 /* WowneroWallet.framework */,
|
||||||
CE6B5DF02BF26AAA00CF1F44 /* wownero_libwallet2_api_c.dylib */,
|
CE4F88302C202CEE007A8C67 /* MoneroWallet.framework */,
|
||||||
9740EEB11CF90186004384FC /* Flutter */,
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
|
@ -192,9 +192,9 @@
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
|
CE6B5DEA2BF26A3300CF1F44 /* CopyFiles */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
FD1CA371131604E6658D4146 /* [CP] Embed Pods Frameworks */,
|
FD1CA371131604E6658D4146 /* [CP] Embed Pods Frameworks */,
|
||||||
CE6B5DEA2BF26A3300CF1F44 /* CopyFiles */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
|
@ -341,6 +341,8 @@
|
||||||
"${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework",
|
"${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework",
|
"${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework",
|
"${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework",
|
||||||
|
"${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework",
|
||||||
|
"${BUILT_PRODUCTS_DIR}/sqlite3_flutter_libs/sqlite3_flutter_libs.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/stack_wallet_backup/stack_wallet_backup.framework",
|
"${BUILT_PRODUCTS_DIR}/stack_wallet_backup/stack_wallet_backup.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/tor/tor.framework",
|
"${BUILT_PRODUCTS_DIR}/tor/tor.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework",
|
"${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework",
|
||||||
|
@ -374,6 +376,8 @@
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework",
|
||||||
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework",
|
||||||
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3_flutter_libs.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/stack_wallet_backup.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/stack_wallet_backup.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/tor.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/tor.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework",
|
||||||
|
@ -486,6 +490,7 @@
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
"$(PROJECT_DIR)/../crypto_plugins/flutter_liblelantus/scripts/ios/mobileliblelantus",
|
"$(PROJECT_DIR)/../crypto_plugins/flutter_liblelantus/scripts/ios/mobileliblelantus",
|
||||||
"$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios",
|
"$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios",
|
||||||
|
"$(PROJECT_DIR)",
|
||||||
);
|
);
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
@ -677,6 +682,7 @@
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
"$(PROJECT_DIR)/../crypto_plugins/flutter_liblelantus/scripts/ios/mobileliblelantus",
|
"$(PROJECT_DIR)/../crypto_plugins/flutter_liblelantus/scripts/ios/mobileliblelantus",
|
||||||
"$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**",
|
"$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**",
|
||||||
|
"$(PROJECT_DIR)",
|
||||||
);
|
);
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
@ -760,6 +766,7 @@
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
"$(PROJECT_DIR)/../crypto_plugins/flutter_liblelantus/scripts/ios/mobileliblelantus/**",
|
"$(PROJECT_DIR)/../crypto_plugins/flutter_liblelantus/scripts/ios/mobileliblelantus/**",
|
||||||
"$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios",
|
"$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios",
|
||||||
|
"$(PROJECT_DIR)",
|
||||||
);
|
);
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
|
|
@ -49,8 +49,8 @@ dependencies:
|
||||||
|
|
||||||
monero:
|
monero:
|
||||||
git:
|
git:
|
||||||
url: https://www.github.com/mrcyjanek/monero.dart
|
url: https://github.com/mrcyjanek/monero.dart
|
||||||
ref: 6a17a405a1a260fa228b2f4fc94044088a4335ac
|
ref: d46753eca865e9e56c2f0ef6fe485c42e11982c5
|
||||||
|
|
||||||
flutter_libepiccash:
|
flutter_libepiccash:
|
||||||
path: ./crypto_plugins/flutter_libepiccash
|
path: ./crypto_plugins/flutter_libepiccash
|
||||||
|
@ -213,8 +213,8 @@ dependency_overrides:
|
||||||
|
|
||||||
monero:
|
monero:
|
||||||
git:
|
git:
|
||||||
url: https://www.github.com/mrcyjanek/monero.dart
|
url: https://github.com/mrcyjanek/monero.dart
|
||||||
ref: 6a17a405a1a260fa228b2f4fc94044088a4335ac
|
ref: d46753eca865e9e56c2f0ef6fe485c42e11982c5
|
||||||
|
|
||||||
bip47:
|
bip47:
|
||||||
git:
|
git:
|
||||||
|
|
Loading…
Reference in a new issue