diff --git a/CHANGELOG.md b/CHANGELOG.md index c7b9b6bf6..e0d7f0975 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- Display Synthetic USD balance in the account overview screen. + ## [1.2.3] - 2023-08-28 -- Add synthetic usd feature. +- Add synthetic USD feature. - Fix delayed position update. - Change contract duration to 7 days. - Add settings in coordinator to make contract fee rate configurable during runtime. diff --git a/mobile/lib/features/stable/stable_screen.dart b/mobile/lib/features/stable/stable_screen.dart index 45a8e54a4..4efd448a3 100644 --- a/mobile/lib/features/stable/stable_screen.dart +++ b/mobile/lib/features/stable/stable_screen.dart @@ -96,8 +96,7 @@ class _StableScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ FiatText( - amount: - position != null && position.direction != Direction.long ? position.quantity : 0, + amount: positionChangeNotifier.getStableUSDAmountInFiat(), textStyle: const TextStyle(fontSize: 30, fontWeight: FontWeight.bold), ) ], diff --git a/mobile/lib/features/trade/position_change_notifier.dart b/mobile/lib/features/trade/position_change_notifier.dart index d801b3bc7..8870bc034 100644 --- a/mobile/lib/features/trade/position_change_notifier.dart +++ b/mobile/lib/features/trade/position_change_notifier.dart @@ -5,6 +5,8 @@ import 'package:get_10101/common/application/event_service.dart'; import 'package:get_10101/common/domain/model.dart'; import 'package:get_10101/features/trade/application/position_service.dart'; import 'package:get_10101/features/trade/domain/contract_symbol.dart'; +import 'package:get_10101/features/trade/domain/direction.dart'; +import 'package:get_10101/features/trade/domain/leverage.dart'; import 'domain/position.dart'; import 'domain/price.dart'; @@ -16,6 +18,32 @@ class PositionChangeNotifier extends ChangeNotifier implements Subscriber { Price? price; + /// Amount of stabilised bitcoin in terms of USD (fiat) + double getStableUSDAmountInFiat() { + if (hasStableUSD()) { + final positionUsd = positions[ContractSymbol.btcusd]; + return positionUsd!.quantity; + } else { + return 0.0; + } + } + + Amount getStableUSDAmountInSats() { + if (hasStableUSD()) { + final positionUsd = positions[ContractSymbol.btcusd]; + return positionUsd!.getAmountWithUnrealizedPnl(); + } else { + return Amount(0); + } + } + + bool hasStableUSD() { + final positionUsd = positions[ContractSymbol.btcusd]; + return positionUsd != null && + positionUsd.direction == Direction.short && + positionUsd.leverage == Leverage(1); + } + Future initialize() async { List positions = await _positionService.fetchPositions(); for (Position position in positions) { diff --git a/mobile/lib/features/wallet/balance_row.dart b/mobile/lib/features/wallet/balance_row.dart index 95a09f2fa..01b636d37 100644 --- a/mobile/lib/features/wallet/balance_row.dart +++ b/mobile/lib/features/wallet/balance_row.dart @@ -2,6 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:get_10101/common/amount_text.dart'; import 'package:get_10101/common/domain/model.dart'; +import 'package:get_10101/common/fiat_text.dart'; +import 'package:get_10101/features/stable/stable_screen.dart'; +import 'package:get_10101/features/trade/position_change_notifier.dart'; import 'package:get_10101/features/wallet/create_invoice_screen.dart'; import 'package:get_10101/features/wallet/domain/wallet_history.dart'; import 'package:get_10101/features/wallet/send_screen.dart'; @@ -40,8 +43,10 @@ class _BalanceRowState extends State with SingleTickerProviderStateM Widget build(BuildContext context) { WalletTheme theme = Theme.of(context).extension()!; WalletChangeNotifier walletChangeNotifier = context.watch(); - TextStyle normal = const TextStyle(fontSize: 16.0); - TextStyle bold = const TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0); + const normal = TextStyle(fontSize: 16.0); + const bold = TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0); + + PositionChangeNotifier positionChangeNotifier = context.watch(); Amount amount; String name; @@ -53,6 +58,12 @@ class _BalanceRowState extends State with SingleTickerProviderStateM rowBgColor = theme.lightning; icon = SvgPicture.asset("assets/Lightning_logo.svg"); amount = walletChangeNotifier.lightning(); + } else if (widget.walletType == WalletHistoryItemDataType.stable) { + name = "Synthetic-USD"; + rowBgColor = theme.lightning; + icon = SvgPicture.asset("assets/USD_logo.svg"); + // this in unused for now, other than to initialise value (and satisfy the compiler) + amount = positionChangeNotifier.getStableUSDAmountInSats(); } else { name = "On-chain"; rowBgColor = theme.onChain; @@ -65,12 +76,14 @@ class _BalanceRowState extends State with SingleTickerProviderStateM double buttonSpacing = 10; BalanceRowButton send = BalanceRowButton( + type: widget.walletType, flow: PaymentFlow.outbound, enabled: _expanded, buttonSize: buttonSize, ); BalanceRowButton receive = BalanceRowButton( + type: widget.walletType, flow: PaymentFlow.inbound, enabled: _expanded, buttonSize: buttonSize, @@ -129,7 +142,14 @@ class _BalanceRowState extends State with SingleTickerProviderStateM child: SizedBox(height: widget.iconSize, width: widget.iconSize, child: icon), ), Expanded(child: Text(name, style: normal)), - AmountText(amount: amount, textStyle: bold), + if (widget.walletType == WalletHistoryItemDataType.stable) + // we need to use different widget as we display the value in dollar terms + FiatText( + amount: positionChangeNotifier.getStableUSDAmountInFiat(), + textStyle: bold, + ) + else + AmountText(amount: amount, textStyle: bold), ]), ), ), @@ -142,12 +162,17 @@ class _BalanceRowState extends State with SingleTickerProviderStateM } class BalanceRowButton extends StatelessWidget { + final WalletHistoryItemDataType type; final PaymentFlow flow; final bool enabled; final double buttonSize; const BalanceRowButton( - {super.key, required this.flow, required this.enabled, this.buttonSize = 40}); + {super.key, + required this.type, + required this.flow, + required this.enabled, + this.buttonSize = 40}); double width() { // 2x padding from around the icon, 2x padding from inside the icon @@ -171,6 +196,16 @@ class BalanceRowButton extends StatelessWidget { onPressed: !enabled ? null : () { + if (type == WalletHistoryItemDataType.stable) { + if (flow == PaymentFlow.outbound) { + // eventually there should be a way to send stable sats directly + context.go(StableScreen.route); + } else { + // eventually there should be a way to receive stable sats directly + context.go(StableScreen.route); + } + return; + } if (flow == PaymentFlow.outbound) { context.go(SendScreen.route); } else { diff --git a/mobile/lib/features/wallet/domain/wallet_history.dart b/mobile/lib/features/wallet/domain/wallet_history.dart index 6ba2b3abd..b4decbd8b 100644 --- a/mobile/lib/features/wallet/domain/wallet_history.dart +++ b/mobile/lib/features/wallet/domain/wallet_history.dart @@ -2,7 +2,14 @@ import 'package:get_10101/common/domain/model.dart'; import 'payment_flow.dart'; import 'package:get_10101/bridge_generated/bridge_definitions.dart' as rust; -enum WalletHistoryItemDataType { lightning, onChain, trade, orderMatchingFee, jitChannelFee } +enum WalletHistoryItemDataType { + lightning, + onChain, + trade, + orderMatchingFee, + jitChannelFee, + stable +} enum WalletHistoryStatus { pending, confirmed } diff --git a/mobile/lib/features/wallet/wallet_history_item.dart b/mobile/lib/features/wallet/wallet_history_item.dart index af5119022..ff54703a7 100644 --- a/mobile/lib/features/wallet/wallet_history_item.dart +++ b/mobile/lib/features/wallet/wallet_history_item.dart @@ -69,6 +69,8 @@ class WalletHistoryItem extends StatelessWidget { return "Matching fee"; case WalletHistoryItemDataType.jitChannelFee: return "Channel opening fee"; + case WalletHistoryItemDataType.stable: + return "Stable"; } }(); @@ -81,6 +83,8 @@ class WalletHistoryItem extends StatelessWidget { return "off-chain"; case WalletHistoryItemDataType.onChain: return "on-chain"; + case WalletHistoryItemDataType.stable: + return "stable sats"; } }(); @@ -169,6 +173,7 @@ class WalletHistoryItem extends StatelessWidget { case WalletHistoryItemDataType.onChain: return [HistoryDetail(label: "Transaction id", value: data.txid ?? "")]; case WalletHistoryItemDataType.trade: + case WalletHistoryItemDataType.stable: case WalletHistoryItemDataType.orderMatchingFee: final orderId = data.orderId!.substring(0, 8); return [HistoryDetail(label: "Order", value: orderId)]; diff --git a/mobile/lib/features/wallet/wallet_screen.dart b/mobile/lib/features/wallet/wallet_screen.dart index 95bfd2801..a8d93e786 100644 --- a/mobile/lib/features/wallet/wallet_screen.dart +++ b/mobile/lib/features/wallet/wallet_screen.dart @@ -1,8 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:get_10101/common/amount_text.dart'; +import 'package:get_10101/common/fiat_text.dart'; import 'package:get_10101/common/submission_status_dialog.dart'; import 'package:get_10101/common/value_data_row.dart'; +import 'package:get_10101/features/trade/position_change_notifier.dart'; import 'package:get_10101/features/wallet/seed_screen.dart'; import 'package:get_10101/features/wallet/send_payment_change_notifier.dart'; import 'package:get_10101/util/preferences.dart'; @@ -39,9 +41,11 @@ class _WalletScreenState extends State { @override Widget build(BuildContext context) { - WalletChangeNotifier walletChangeNotifier = context.watch(); - SendPaymentChangeNotifier sendPaymentChangeNotifier = - context.watch(); + final walletChangeNotifier = context.watch(); + final sendPaymentChangeNotifier = context.watch(); + + // For displaying synthetic USD balance + final positionChangeNotifier = context.watch(); if (sendPaymentChangeNotifier.pendingPayment != null && !sendPaymentChangeNotifier.pendingPayment!.displayed) { @@ -138,10 +142,31 @@ class _WalletScreenState extends State { fontStyle: FontStyle.italic, ), ) - : AmountText( - amount: walletChangeNotifier.total(), - textStyle: const TextStyle( - fontSize: 20.0, fontWeight: FontWeight.bold))), + : Row( + children: [ + AmountText( + amount: walletChangeNotifier.total(), + textStyle: const TextStyle( + fontSize: 20.0, fontWeight: FontWeight.bold)), + Visibility( + visible: + positionChangeNotifier.getStableUSDAmountInFiat() != + 0.0, + child: Row( + children: [ + const SizedBox(width: 5), + const Text("+"), + const SizedBox(width: 5), + FiatText( + amount: positionChangeNotifier + .getStableUSDAmountInFiat(), + textStyle: const TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold)), + ], + )), + ], + )), ], ); }, @@ -151,6 +176,7 @@ class _WalletScreenState extends State { children: [ BalanceRow(walletType: WalletHistoryItemDataType.lightning), BalanceRow(walletType: WalletHistoryItemDataType.onChain), + BalanceRow(walletType: WalletHistoryItemDataType.stable), ], ), ), diff --git a/mobile/macos/Podfile.lock b/mobile/macos/Podfile.lock index 84a34c117..c46a12d6b 100644 --- a/mobile/macos/Podfile.lock +++ b/mobile/macos/Podfile.lock @@ -1,6 +1,4 @@ PODS: - - device_info_plus (0.0.1): - - FlutterMacOS - Firebase/CoreOnly (10.12.0): - FirebaseCore (= 10.12.0) - Firebase/Messaging (10.12.0): @@ -74,11 +72,8 @@ PODS: - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS - - url_launcher_macos (0.0.1): - - FlutterMacOS DEPENDENCIES: - - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) - firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`) - firebase_messaging (from `Flutter/ephemeral/.symlinks/plugins/firebase_messaging/macos`) - flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`) @@ -87,7 +82,6 @@ DEPENDENCIES: - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) SPEC REPOS: trunk: @@ -102,8 +96,6 @@ SPEC REPOS: - PromisesObjC EXTERNAL SOURCES: - device_info_plus: - :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos firebase_core: :path: Flutter/ephemeral/.symlinks/plugins/firebase_core/macos firebase_messaging: @@ -120,11 +112,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos shared_preferences_foundation: :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin - url_launcher_macos: - :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos SPEC CHECKSUMS: - device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f Firebase: 07150e75d142fb9399f6777fa56a187b17f833a0 firebase_core: ff59797157ca9adda4440071643761b41fcd03b3 firebase_messaging: d489df2f5cf5eb4b1ffb0b920f1d8c6b911f6166 @@ -142,7 +131,6 @@ SPEC CHECKSUMS: PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 share_plus: 76dd39142738f7a68dd57b05093b5e8193f220f7 shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 - url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 PODFILE CHECKSUM: f429f80f5470aff39540e8333365097246b857cb diff --git a/mobile/native/src/event/api.rs b/mobile/native/src/event/api.rs index 286489b70..41638bad8 100644 --- a/mobile/native/src/event/api.rs +++ b/mobile/native/src/event/api.rs @@ -84,7 +84,6 @@ pub struct FlutterSubscriber { /// Subscribes to event relevant for flutter and forwards them to the stream sink. impl Subscriber for FlutterSubscriber { fn notify(&self, event: &EventInternal) { - tracing::debug!(event = %event, "Forwarding event to flutter"); self.stream.add(event.clone().into()); }