Peg in and peg out flow (#1745)

* version 4.20.0 * update build numbers * UI updates and script fix for ios bundle identifier * disable mweb for desktop * change hardcoded ltc server ip address electrum connection enhancement * additional logging and minor fixes * additional logging and minor fixes * addresses pt.1 * logs of fixes and experimental changes, close wallet before opening next * save * fix icon * fixes * [skip ci] updates * [skip ci] updates * updates * minor optimizations * fix for when switching between wallets * [skip ci] updates * [skip ci] updates * Update cw_bitcoin/lib/litecoin_wallet.dart Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> * Update cw_bitcoin/lib/litecoin_wallet.dart Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> * mobx * mostly logging * stream fix pt.1 [skip ci] * updates * some fixes and enhancements * [skip ci] minor * potential partial fix for streamsink closed * fix stream sink closed errors * fix mweb logo colors * add initial whitelisting for coin types on send screen * MWEB enhancements 2.0 (#1735) * additional logging and minor fixes * additional logging and minor fixes * addresses pt.1 * Allow Wallet Group Names to be the same as Wallet Names (#1730) * fix: Issues with imaging * fix: Allow group names to be the same as wallet names * fix: Bug with wallet grouping when a wallet is minimized * fix: Bug with wallet grouping when a wallet is minimized * logs of fixes and experimental changes, close wallet before opening next * save * fix icon * fixes * [skip ci] updates * [skip ci] updates * updates * minor optimizations * fix for when switching between wallets * [skip ci] updates * [skip ci] updates * Update cw_bitcoin/lib/litecoin_wallet.dart Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> * Update cw_bitcoin/lib/litecoin_wallet.dart Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> * mobx * mostly logging * stream fix pt.1 [skip ci] * updates * some fixes and enhancements * [skip ci] minor * potential partial fix for streamsink closed * fix stream sink closed errors * fix mweb logo colors * save * minor enhancements [skip ci] * save * experimental * minor * minor [skip ci] --------- Co-authored-by: David Adegoke <64401859+Blazebrain@users.noreply.github.com> Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> * fix menu list removing from original list * handle pegin and pegout * fix text color * fix import * pegin/out button ui updates * update spacing + tx creation fix * add correct args for link view model [skip ci] --------- Co-authored-by: Matthew Fosse <matt@fosse.co> Co-authored-by: fossephate <matt.cfosse@gmail.com> Co-authored-by: David Adegoke <64401859+Blazebrain@users.noreply.github.com>

Omar Hatem committed Oct 15, 2024 at 00:28 UTC ebe8c65407774c49547c2ba86f6ea83c260a8919
14 files changed +428 -253
cw_bitcoin/lib/bitcoin_transaction_credentials.dart
+3 -1
@@ -1,11 +1,13 @@
1 import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
2 import 'package:cw_core/output_info.dart';
3 +import 'package:cw_core/unspent_coin_type.dart';
4
5 class BitcoinTransactionCredentials {
6 BitcoinTransactionCredentials(this.outputs,
6 - {required this.priority, this.feeRate});
7 + {required this.priority, this.feeRate, this.coinTypeToSpendFrom = UnspentCoinType.any});
8
9 final List<OutputInfo> outputs;
10 final BitcoinTransactionPriority? priority;
11 final int? feeRate;
12 + final UnspentCoinType coinTypeToSpendFrom;
13 }
cw_bitcoin/lib/electrum_wallet.dart
+27 -1
@@ -37,6 +37,7 @@ import 'package:cw_core/wallet_info.dart';
37 import 'package:cw_core/wallet_keys_file.dart';
38 import 'package:cw_core/wallet_type.dart';
39 import 'package:cw_core/get_height_by_date.dart';
40 +import 'package:cw_core/unspent_coin_type.dart';
41 import 'package:flutter/foundation.dart';
42 import 'package:hive/hive.dart';
43 import 'package:mobx/mobx.dart';
@@ -584,6 +585,7 @@ abstract class ElectrumWalletBase
585 required int credentialsAmount,
586 required bool paysToSilentPayment,
587 int? inputsCount,
588 + UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
589 }) {
590 List<UtxoWithAddress> utxos = [];
591 List<Outpoint> vinOutpoints = [];
@@ -594,7 +596,20 @@ abstract class ElectrumWalletBase
596 bool spendsUnconfirmedTX = false;
597
598 int leftAmount = credentialsAmount;
597 - final availableInputs = unspentCoins.where((utx) => utx.isSending && !utx.isFrozen).toList();
599 + final availableInputs = unspentCoins.where((utx) {
600 + if (!utx.isSending || utx.isFrozen) {
601 + return false;
602 + }
603 +
604 + switch (coinTypeToSpendFrom) {
605 + case UnspentCoinType.mweb:
606 + return utx.bitcoinAddressRecord.type == SegwitAddresType.mweb;
607 + case UnspentCoinType.nonMweb:
608 + return utx.bitcoinAddressRecord.type != SegwitAddresType.mweb;
609 + case UnspentCoinType.any:
610 + return true;
611 + }
612 + }).toList();
613 final unconfirmedCoins = availableInputs.where((utx) => utx.confirmations == 0).toList();
614
615 for (int i = 0; i < availableInputs.length; i++) {
@@ -701,11 +716,13 @@ abstract class ElectrumWalletBase
716 String? memo,
717 int credentialsAmount = 0,
718 bool hasSilentPayment = false,
719 + UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
720 }) async {
721 final utxoDetails = _createUTXOS(
722 sendAll: true,
723 credentialsAmount: credentialsAmount,
724 paysToSilentPayment: hasSilentPayment,
725 + coinTypeToSpendFrom: coinTypeToSpendFrom,
726 );
727
728 int fee = await calcFee(
@@ -772,12 +789,14 @@ abstract class ElectrumWalletBase
789 String? memo,
790 bool? useUnconfirmed,
791 bool hasSilentPayment = false,
792 + UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
793 }) async {
794 final utxoDetails = _createUTXOS(
795 sendAll: false,
796 credentialsAmount: credentialsAmount,
797 inputsCount: inputsCount,
798 paysToSilentPayment: hasSilentPayment,
799 + coinTypeToSpendFrom: coinTypeToSpendFrom,
800 );
801
802 final spendingAllCoins = utxoDetails.availableInputs.length == utxoDetails.utxos.length;
@@ -797,6 +816,7 @@ abstract class ElectrumWalletBase
816 inputsCount: utxoDetails.utxos.length + 1,
817 memo: memo,
818 hasSilentPayment: hasSilentPayment,
819 + coinTypeToSpendFrom: coinTypeToSpendFrom,
820 );
821 }
822
@@ -855,6 +875,7 @@ abstract class ElectrumWalletBase
875 inputsCount: utxoDetails.utxos.length + 1,
876 memo: memo,
877 useUnconfirmed: useUnconfirmed ?? spendingAllConfirmedCoins,
878 + coinTypeToSpendFrom: coinTypeToSpendFrom,
879 );
880 }
881
@@ -862,6 +883,7 @@ abstract class ElectrumWalletBase
883 outputs,
884 feeRate,
885 memo: memo,
886 + coinTypeToSpendFrom: coinTypeToSpendFrom,
887 );
888
889 if (estimatedSendAll.amount == credentialsAmount) {
@@ -900,6 +922,7 @@ abstract class ElectrumWalletBase
922 memo: memo,
923 useUnconfirmed: useUnconfirmed ?? spendingAllConfirmedCoins,
924 hasSilentPayment: hasSilentPayment,
925 + coinTypeToSpendFrom: coinTypeToSpendFrom,
926 );
927 }
928 }
@@ -957,6 +980,7 @@ abstract class ElectrumWalletBase
980 final hasMultiDestination = transactionCredentials.outputs.length > 1;
981 final sendAll = !hasMultiDestination && transactionCredentials.outputs.first.sendAll;
982 final memo = transactionCredentials.outputs.first.memo;
983 + final coinTypeToSpendFrom = transactionCredentials.coinTypeToSpendFrom;
984
985 int credentialsAmount = 0;
986 bool hasSilentPayment = false;
@@ -1012,6 +1036,7 @@ abstract class ElectrumWalletBase
1036 memo: memo,
1037 credentialsAmount: credentialsAmount,
1038 hasSilentPayment: hasSilentPayment,
1039 + coinTypeToSpendFrom: coinTypeToSpendFrom,
1040 );
1041 } else {
1042 estimatedTx = await estimateTxForAmount(
@@ -1020,6 +1045,7 @@ abstract class ElectrumWalletBase
1045 feeRateInt,
1046 memo: memo,
1047 hasSilentPayment: hasSilentPayment,
1048 + coinTypeToSpendFrom: coinTypeToSpendFrom,
1049 );
1050 }
1051
cw_bitcoin/lib/litecoin_wallet.dart
+6 -1
@@ -251,7 +251,11 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
251 _syncTimer?.cancel();
252 try {
253 syncStatus = SyncronizingSyncStatus();
254 - await subscribeForUpdates();
254 + try {
255 + await subscribeForUpdates();
256 + } catch (e) {
257 + print("failed to subcribe for updates: $e");
258 + }
259 updateFeeRates();
260 _feeRatesTimer?.cancel();
261 _feeRatesTimer =
@@ -916,6 +920,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
920 }
921
922 if (!hasMwebInput && !hasMwebOutput) {
923 + tx.isMweb = false;
924 return tx;
925 }
926
cw_bitcoin/pubspec.lock
+18 -10
@@ -21,10 +21,10 @@ packages:
21 dependency: transitive
22 description:
23 name: archive
24 - sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
24 + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
25 url: "https://pub.dev"
26 source: hosted
27 - version: "3.4.10"
27 + version: "3.6.1"
28 args:
29 dependency: transitive
30 description:
@@ -336,10 +336,10 @@ packages:
336 dependency: transitive
337 description:
338 name: file
339 - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
339 + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
340 url: "https://pub.dev"
341 source: hosted
342 - version: "7.0.0"
342 + version: "7.0.1"
343 fixnum:
344 dependency: transitive
345 description:
@@ -403,14 +403,22 @@ packages:
403 url: "https://pub.dev"
404 source: hosted
405 version: "2.1.2"
406 + google_identity_services_web:
407 + dependency: transitive
408 + description:
409 + name: google_identity_services_web
410 + sha256: "5be191523702ba8d7a01ca97c17fca096822ccf246b0a9f11923a6ded06199b6"
411 + url: "https://pub.dev"
412 + source: hosted
413 + version: "0.3.1+4"
414 googleapis_auth:
415 dependency: transitive
416 description:
417 name: googleapis_auth
410 - sha256: af7c3a3edf9d0de2e1e0a77e994fae0a581c525fa7012af4fa0d4a52ed9484da
418 + sha256: befd71383a955535060acde8792e7efc11d2fccd03dd1d3ec434e85b68775938
419 url: "https://pub.dev"
420 source: hosted
413 - version: "1.4.1"
421 + version: "1.6.0"
422 graphs:
423 dependency: transitive
424 description:
@@ -809,10 +817,10 @@ packages:
817 dependency: transitive
818 description:
819 name: shared_preferences_foundation
812 - sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f
820 + sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d"
821 url: "https://pub.dev"
822 source: hosted
815 - version: "2.5.2"
823 + version: "2.5.3"
824 shared_preferences_linux:
825 dependency: transitive
826 description:
@@ -1031,10 +1039,10 @@ packages:
1039 dependency: transitive
1040 description:
1041 name: xdg_directories
1034 - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
1042 + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
1043 url: "https://pub.dev"
1044 source: hosted
1037 - version: "1.0.4"
1045 + version: "1.1.0"
1046 yaml:
1047 dependency: transitive
1048 description:
cw_core/lib/unspent_coin_type.dart new
+1
@@ -0,0 +1 @@
1 +enum UnspentCoinType { mweb, nonMweb, any }
\ No newline at end of file
lib/bitcoin/cw_bitcoin.dart
+36 -26
@@ -106,33 +106,32 @@ class CWBitcoin extends Bitcoin {
106 }
107
108 @override
109 - Object createBitcoinTransactionCredentials(List<Output> outputs,
110 - {required TransactionPriority priority, int? feeRate}) {
109 + Object createBitcoinTransactionCredentials(
110 + List<Output> outputs, {
111 + required TransactionPriority priority,
112 + int? feeRate,
113 + UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
114 + }) {
115 final bitcoinFeeRate =
116 priority == BitcoinTransactionPriority.custom && feeRate != null ? feeRate : null;
117 return BitcoinTransactionCredentials(
114 - outputs
115 - .map((out) => OutputInfo(
116 - fiatAmount: out.fiatAmount,
117 - cryptoAmount: out.cryptoAmount,
118 - address: out.address,
119 - note: out.note,
120 - sendAll: out.sendAll,
121 - extractedAddress: out.extractedAddress,
122 - isParsedAddress: out.isParsedAddress,
123 - formattedCryptoAmount: out.formattedCryptoAmount,
124 - memo: out.memo))
125 - .toList(),
126 - priority: priority as BitcoinTransactionPriority,
127 - feeRate: bitcoinFeeRate);
128 - }
129 -
130 - @override
131 - Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs,
132 - {TransactionPriority? priority, required int feeRate}) =>
133 - BitcoinTransactionCredentials(outputs,
134 - priority: priority != null ? priority as BitcoinTransactionPriority : null,
135 - feeRate: feeRate);
118 + outputs
119 + .map((out) => OutputInfo(
120 + fiatAmount: out.fiatAmount,
121 + cryptoAmount: out.cryptoAmount,
122 + address: out.address,
123 + note: out.note,
124 + sendAll: out.sendAll,
125 + extractedAddress: out.extractedAddress,
126 + isParsedAddress: out.isParsedAddress,
127 + formattedCryptoAmount: out.formattedCryptoAmount,
128 + memo: out.memo))
129 + .toList(),
130 + priority: priority as BitcoinTransactionPriority,
131 + feeRate: bitcoinFeeRate,
132 + coinTypeToSpendFrom: coinTypeToSpendFrom,
133 + );
134 + }
135
136 @override
137 @computed
@@ -205,9 +204,20 @@ class CWBitcoin extends Bitcoin {
204 (priority as BitcoinTransactionPriority).labelWithRate(rate, customRate);
205
206 @override
208 - List<BitcoinUnspent> getUnspents(Object wallet) {
207 + List<BitcoinUnspent> getUnspents(Object wallet,
208 + {UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any}) {
209 final bitcoinWallet = wallet as ElectrumWallet;
210 - return bitcoinWallet.unspentCoins;
210 + return bitcoinWallet.unspentCoins.where((element) {
211 + switch(coinTypeToSpendFrom) {
212 + case UnspentCoinType.mweb:
213 + return element.bitcoinAddressRecord.type == SegwitAddresType.mweb;
214 + case UnspentCoinType.nonMweb:
215 + return element.bitcoinAddressRecord.type != SegwitAddresType.mweb;
216 + case UnspentCoinType.any:
217 + return true;
218 + }
219 +
220 + }).toList();
221 }
222
223 Future<void> updateUnspents(Object wallet) async {
lib/di.dart
+18 -9
@@ -167,6 +167,7 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_i
167 import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
168 import 'package:cake_wallet/view_model/wallet_restore_choose_derivation_view_model.dart';
169 import 'package:cw_core/nano_account.dart';
170 +import 'package:cw_core/unspent_coin_type.dart';
171 import 'package:cw_core/unspent_coins_info.dart';
172 import 'package:cw_core/wallet_service.dart';
173 import 'package:cw_core/transaction_info.dart';
@@ -725,8 +726,8 @@ Future<void> setup({
726 getIt.get<SendTemplateStore>(),
727 getIt.get<FiatConversionStore>()));
728
728 - getIt.registerFactory<SendViewModel>(
729 - () => SendViewModel(
729 + getIt.registerFactoryParam<SendViewModel, UnspentCoinType?, void>(
730 + (coinTypeToSpendFrom, _) => SendViewModel(
731 getIt.get<AppStore>(),
732 getIt.get<SendTemplateViewModel>(),
733 getIt.get<FiatConversionStore>(),
@@ -734,12 +735,13 @@ Future<void> setup({
735 getIt.get<ContactListViewModel>(),
736 _transactionDescriptionBox,
737 getIt.get<AppStore>().wallet!.isHardwareWallet ? getIt.get<LedgerViewModel>() : null,
738 + coinTypeToSpendFrom: coinTypeToSpendFrom ?? UnspentCoinType.any,
739 ),
740 );
741
740 - getIt.registerFactoryParam<SendPage, PaymentRequest?, void>(
741 - (PaymentRequest? initialPaymentRequest, _) => SendPage(
742 - sendViewModel: getIt.get<SendViewModel>(),
742 + getIt.registerFactoryParam<SendPage, PaymentRequest?, UnspentCoinType?>(
743 + (PaymentRequest? initialPaymentRequest, coinTypeToSpendFrom) => SendPage(
744 + sendViewModel: getIt.get<SendViewModel>(param1: coinTypeToSpendFrom),
745 authService: getIt.get<AuthService>(),
746 initialPaymentRequest: initialPaymentRequest,
747 ));
@@ -1215,14 +1217,21 @@ Future<void> setup({
1217
1218 getIt.registerFactory(() => SupportOtherLinksPage(getIt.get<SupportViewModel>()));
1219
1218 - getIt.registerFactory(() {
1220 + getIt.registerFactoryParam<UnspentCoinsListViewModel, UnspentCoinType?, void>(
1221 + (coinTypeToSpendFrom, _) {
1222 final wallet = getIt.get<AppStore>().wallet;
1223
1221 - return UnspentCoinsListViewModel(wallet: wallet!, unspentCoinsInfo: _unspentCoinsInfoSource);
1224 + return UnspentCoinsListViewModel(
1225 + wallet: wallet!,
1226 + unspentCoinsInfo: _unspentCoinsInfoSource,
1227 + coinTypeToSpendFrom: coinTypeToSpendFrom ?? UnspentCoinType.any,
1228 + );
1229 });
1230
1224 - getIt.registerFactory(() =>
1225 - UnspentCoinsListPage(unspentCoinsListViewModel: getIt.get<UnspentCoinsListViewModel>()));
1231 + getIt.registerFactoryParam<UnspentCoinsListPage, UnspentCoinType?, void>(
1232 + (coinTypeToSpendFrom, _) => UnspentCoinsListPage(
1233 + unspentCoinsListViewModel:
1234 + getIt.get<UnspentCoinsListViewModel>(param1: coinTypeToSpendFrom)));
1235
1236 getIt.registerFactoryParam<UnspentCoinsDetailsViewModel, UnspentCoinsItem,
1237 UnspentCoinsListViewModel>(
lib/router.dart
+16 -8
@@ -120,6 +120,7 @@ import 'package:cw_core/crypto_currency.dart';
120 import 'package:cw_core/nano_account.dart';
121 import 'package:cw_core/node.dart';
122 import 'package:cw_core/transaction_info.dart';
123 +import 'package:cw_core/unspent_coin_type.dart';
124 import 'package:cw_core/wallet_info.dart';
125 import 'package:cw_core/wallet_type.dart';
126 import 'package:flutter/cupertino.dart';
@@ -184,7 +185,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
185 final type = settings.arguments as WalletType;
186 final walletGroupsDisplayVM = getIt.get<WalletGroupsDisplayViewModel>(param1: type);
187
187 - return CupertinoPageRoute<void>(builder: (_) => WalletGroupsDisplayPage(walletGroupsDisplayVM));
188 + return CupertinoPageRoute<void>(
189 + builder: (_) => WalletGroupsDisplayPage(walletGroupsDisplayVM));
190
191 case Routes.newWallet:
192 final args = settings.arguments as NewWalletArguments;
@@ -348,13 +350,17 @@ Route<dynamic> createRoute(RouteSettings settings) {
350 settings: settings, builder: (_) => getIt.get<DashboardPage>());
351
352 case Routes.send:
351 - final initialPaymentRequest = settings.arguments as PaymentRequest?;
353 + final args = settings.arguments as Map<String, dynamic>?;
354 + final initialPaymentRequest = args?['paymentRequest'] as PaymentRequest?;
355 + final coinTypeToSpendFrom = args?['coinTypeToSpendFrom'] as UnspentCoinType?;
356
357 return CupertinoPageRoute<void>(
354 - fullscreenDialog: true,
355 - builder: (_) => getIt.get<SendPage>(
356 - param1: initialPaymentRequest,
357 - ));
358 + fullscreenDialog: true,
359 + builder: (_) => getIt.get<SendPage>(
360 + param1: initialPaymentRequest,
361 + param2: coinTypeToSpendFrom,
362 + ),
363 + );
364
365 case Routes.sendTemplate:
366 return CupertinoPageRoute<void>(
@@ -604,7 +610,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
610 fullscreenDialog: true, builder: (_) => getIt.get<SupportOtherLinksPage>());
611
612 case Routes.unspentCoinsList:
607 - return MaterialPageRoute<void>(builder: (_) => getIt.get<UnspentCoinsListPage>());
613 + final coinTypeToSpendFrom = settings.arguments as UnspentCoinType?;
614 + return MaterialPageRoute<void>(
615 + builder: (_) => getIt.get<UnspentCoinsListPage>(param1: coinTypeToSpendFrom));
616
617 case Routes.unspentCoinsDetails:
618 final args = settings.arguments as List;
@@ -778,7 +786,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
786
787 case Routes.walletGroupDescription:
788 final walletType = settings.arguments as WalletType;
781 -
789 +
790 return MaterialPageRoute<void>(
791 builder: (_) => WalletGroupDescriptionPage(
792 selectedWalletType: walletType,
lib/src/screens/dashboard/pages/balance_page.dart
+264 -178
@@ -17,13 +17,15 @@ import 'package:cake_wallet/src/widgets/standard_switch.dart';
17 import 'package:cake_wallet/store/settings_store.dart';
18 import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
19 import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
20 +import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
21 import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
22 import 'package:cake_wallet/utils/feature_flag.dart';
23 +import 'package:cake_wallet/utils/payment_request.dart';
24 import 'package:cake_wallet/utils/show_pop_up.dart';
25 import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
26 import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
27 import 'package:cw_core/crypto_currency.dart';
26 -import 'package:flutter/cupertino.dart';
28 +import 'package:cw_core/unspent_coin_type.dart';
29 import 'package:flutter/material.dart';
30 import 'package:flutter_mobx/flutter_mobx.dart';
31 import 'package:url_launcher/url_launcher.dart';
@@ -837,216 +839,300 @@ class BalanceRowWidget extends StatelessWidget {
839 color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
840 ),
841 child: Container(
840 - margin: const EdgeInsets.only(top: 0, left: 24, right: 8, bottom: 16),
842 child: Column(
843 crossAxisAlignment: CrossAxisAlignment.start,
844 children: [
844 - Stack(
845 - children: [
846 - if (currency == CryptoCurrency.ltc)
847 - Row(
848 - mainAxisAlignment: MainAxisAlignment.end,
849 - children: [
850 - Container(
851 - padding: EdgeInsets.only(right: 16, top: 16),
852 - child: Column(
853 - children: [
854 - Container(
855 - decoration: BoxDecoration(
856 - color: Colors.white,
857 - shape: BoxShape.circle,
845 + Container(
846 + margin: const EdgeInsets.only(top: 0, left: 24, right: 8, bottom: 16),
847 + child: Stack(
848 + children: [
849 + if (currency == CryptoCurrency.ltc)
850 + Row(
851 + mainAxisAlignment: MainAxisAlignment.end,
852 + children: [
853 + Container(
854 + padding: EdgeInsets.only(right: 16, top: 16),
855 + child: Column(
856 + children: [
857 + Container(
858 + decoration: BoxDecoration(
859 + color: Colors.white,
860 + shape: BoxShape.circle,
861 + ),
862 + child: ImageIcon(
863 + AssetImage('assets/images/mweb_logo.png'),
864 + color: Color.fromARGB(255, 11, 70, 129),
865 + size: 40,
866 + ),
867 ),
859 - child: ImageIcon(
860 - AssetImage('assets/images/mweb_logo.png'),
861 - color: Color.fromARGB(255, 11, 70, 129),
862 - size: 40,
868 + const SizedBox(height: 10),
869 + Text(
870 + 'MWEB',
871 + style: TextStyle(
872 + fontSize: 15,
873 + fontFamily: 'Lato',
874 + fontWeight: FontWeight.w800,
875 + color: Theme.of(context)
876 + .extension<BalancePageTheme>()!
877 + .assetTitleColor,
878 + height: 1,
879 + ),
880 ),
864 - ),
865 - const SizedBox(height: 10),
881 + ],
882 + ),
883 + ),
884 + ],
885 + ),
886 + if (hasSecondAvailableBalance)
887 + Row(
888 + children: [
889 + Column(
890 + crossAxisAlignment: CrossAxisAlignment.start,
891 + children: [
892 + SizedBox(height: 24),
893 Text(
867 - 'MWEB',
894 + '${secondAvailableBalanceLabel}',
895 + textAlign: TextAlign.center,
896 style: TextStyle(
869 - fontSize: 15,
897 + fontSize: 12,
898 fontFamily: 'Lato',
871 - fontWeight: FontWeight.w800,
899 + fontWeight: FontWeight.w400,
900 + color: Theme.of(context)
901 + .extension<BalancePageTheme>()!
902 + .labelTextColor,
903 + height: 1,
904 + ),
905 + ),
906 + SizedBox(height: 8),
907 + AutoSizeText(
908 + secondAvailableBalance,
909 + style: TextStyle(
910 + fontSize: 20,
911 + fontFamily: 'Lato',
912 + fontWeight: FontWeight.w400,
913 color: Theme.of(context)
914 .extension<BalancePageTheme>()!
915 .assetTitleColor,
916 height: 1,
917 ),
918 + maxLines: 1,
919 + textAlign: TextAlign.center,
920 ),
921 + SizedBox(height: 4),
922 + if (!isTestnet)
923 + Text(
924 + '${secondAvailableFiatBalance}',
925 + textAlign: TextAlign.center,
926 + style: TextStyle(
927 + fontSize: 12,
928 + fontFamily: 'Lato',
929 + fontWeight: FontWeight.w400,
930 + color: Theme.of(context)
931 + .extension<BalancePageTheme>()!
932 + .textColor,
933 + height: 1,
934 + ),
935 + ),
936 ],
937 ),
880 - ),
881 - ],
882 - ),
883 - if (hasSecondAvailableBalance)
884 - Row(
885 - children: [
886 - Column(
887 - crossAxisAlignment: CrossAxisAlignment.start,
888 - children: [
889 - SizedBox(height: 24),
890 - Text(
891 - '${secondAvailableBalanceLabel}',
892 - textAlign: TextAlign.center,
893 - style: TextStyle(
894 - fontSize: 12,
895 - fontFamily: 'Lato',
896 - fontWeight: FontWeight.w400,
897 - color: Theme.of(context)
898 - .extension<BalancePageTheme>()!
899 - .labelTextColor,
900 - height: 1,
901 - ),
902 - ),
903 - SizedBox(height: 8),
904 - AutoSizeText(
905 - secondAvailableBalance,
906 - style: TextStyle(
907 - fontSize: 20,
908 - fontFamily: 'Lato',
909 - fontWeight: FontWeight.w400,
910 - color: Theme.of(context)
911 - .extension<BalancePageTheme>()!
912 - .assetTitleColor,
913 - height: 1,
914 - ),
915 - maxLines: 1,
916 - textAlign: TextAlign.center,
917 - ),
918 - SizedBox(height: 4),
919 - if (!isTestnet)
938 + ],
939 + ),
940 + ],
941 + ),
942 + ),
943 + Container(
944 + margin: const EdgeInsets.only(top: 0, left: 24, right: 8, bottom: 16),
945 + child: Stack(
946 + children: [
947 + if (hasSecondAdditionalBalance)
948 + Row(
949 + children: [
950 + Column(
951 + crossAxisAlignment: CrossAxisAlignment.start,
952 + children: [
953 + SizedBox(height: 24),
954 Text(
921 - '${secondAvailableFiatBalance}',
955 + '${secondAdditionalBalanceLabel}',
956 textAlign: TextAlign.center,
957 style: TextStyle(
958 fontSize: 12,
959 fontFamily: 'Lato',
960 fontWeight: FontWeight.w400,
927 - color:
928 - Theme.of(context).extension<BalancePageTheme>()!.textColor,
961 + color: Theme.of(context)
962 + .extension<BalancePageTheme>()!
963 + .labelTextColor,
964 height: 1,
965 ),
966 ),
932 - ],
933 - ),
934 - ],
935 - ),
936 - ],
937 - ),
938 - Stack(
939 - children: [
940 - if (hasSecondAdditionalBalance)
941 - Row(
942 - children: [
943 - Column(
944 - crossAxisAlignment: CrossAxisAlignment.start,
945 - children: [
946 - SizedBox(height: 24),
947 - Text(
948 - '${secondAdditionalBalanceLabel}',
949 - textAlign: TextAlign.center,
950 - style: TextStyle(
951 - fontSize: 12,
952 - fontFamily: 'Lato',
953 - fontWeight: FontWeight.w400,
954 - color: Theme.of(context)
955 - .extension<BalancePageTheme>()!
956 - .labelTextColor,
957 - height: 1,
958 - ),
959 - ),
960 - SizedBox(height: 8),
961 - AutoSizeText(
962 - secondAdditionalBalance,
963 - style: TextStyle(
964 - fontSize: 20,
965 - fontFamily: 'Lato',
966 - fontWeight: FontWeight.w400,
967 - color: Theme.of(context)
968 - .extension<BalancePageTheme>()!
969 - .assetTitleColor,
970 - height: 1,
971 - ),
972 - maxLines: 1,
973 - textAlign: TextAlign.center,
974 - ),
975 - SizedBox(height: 4),
976 - if (!isTestnet)
977 - Text(
978 - '${secondAdditionalFiatBalance}',
979 - textAlign: TextAlign.center,
967 + SizedBox(height: 8),
968 + AutoSizeText(
969 + secondAdditionalBalance,
970 style: TextStyle(
981 - fontSize: 12,
971 + fontSize: 20,
972 fontFamily: 'Lato',
973 fontWeight: FontWeight.w400,
984 - color:
985 - Theme.of(context).extension<BalancePageTheme>()!.textColor,
974 + color: Theme.of(context)
975 + .extension<BalancePageTheme>()!
976 + .assetTitleColor,
977 height: 1,
978 ),
979 + maxLines: 1,
980 + textAlign: TextAlign.center,
981 + ),
982 + SizedBox(height: 4),
983 + if (!isTestnet)
984 + Text(
985 + '${secondAdditionalFiatBalance}',
986 + textAlign: TextAlign.center,
987 + style: TextStyle(
988 + fontSize: 12,
989 + fontFamily: 'Lato',
990 + fontWeight: FontWeight.w400,
991 + color: Theme.of(context)
992 + .extension<BalancePageTheme>()!
993 + .textColor,
994 + height: 1,
995 + ),
996 + ),
997 + ],
998 + ),
999 + ],
1000 + ),
1001 + ],
1002 + ),
1003 + ),
1004 + IntrinsicHeight(
1005 + child: Container(
1006 + padding: EdgeInsets.symmetric(horizontal: 24),
1007 + child: Row(
1008 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
1009 + children: [
1010 + Expanded(
1011 + child: Semantics(
1012 + label: S.of(context).litecoin_mweb_pegin,
1013 + child: OutlinedButton(
1014 + onPressed: () {
1015 + final mwebAddress =
1016 + bitcoin!.getUnusedMwebAddress(dashboardViewModel.wallet);
1017 + PaymentRequest? paymentRequest = null;
1018 + if ((mwebAddress?.isNotEmpty ?? false)) {
1019 + paymentRequest =
1020 + PaymentRequest.fromUri(Uri.parse("litecoin:${mwebAddress}"));
1021 + }
1022 +
1023 + Navigator.pushNamed(
1024 + context,
1025 + Routes.send,
1026 + arguments: {
1027 + 'paymentRequest': paymentRequest,
1028 + 'coinTypeToSpendFrom': UnspentCoinType.nonMweb,
1029 + },
1030 + );
1031 + },
1032 + style: OutlinedButton.styleFrom(
1033 + backgroundColor: Theme.of(context)
1034 + .extension<SendPageTheme>()!
1035 + .textFieldButtonIconColor
1036 + .withAlpha(50),
1037 + side: BorderSide(color: Colors.grey.shade400, width: 0),
1038 + shape: RoundedRectangleBorder(
1039 + borderRadius: BorderRadius.circular(20),
1040 ),
989 - ],
1041 + ),
1042 + child: Container(
1043 + padding: EdgeInsets.symmetric(vertical: 12),
1044 + child: Row(
1045 + mainAxisAlignment: MainAxisAlignment.center,
1046 + children: [
1047 + Image.asset(
1048 + height: 30,
1049 + width: 30,
1050 + 'assets/images/received.png',
1051 + color: Theme.of(context)
1052 + .extension<BalancePageTheme>()!
1053 + .balanceAmountColor,
1054 + ),
1055 + const SizedBox(width: 8),
1056 + Text(
1057 + S.of(context).litecoin_mweb_pegin,
1058 + style: TextStyle(
1059 + color: Theme.of(context)
1060 + .extension<BalancePageTheme>()!
1061 + .assetTitleColor,
1062 + ),
1063 + ),
1064 + ],
1065 + ),
1066 + ),
1067 + ),
1068 ),
991 - ],
992 - ),
993 - // TODO: smarter peg in / out buttons
994 - // if (currency == CryptoCurrency.ltc)
995 - // Row(
996 - // mainAxisAlignment: MainAxisAlignment.end,
997 - // children: [
998 - // Container(
999 - // margin: EdgeInsets.only(top: 24, right: 8),
1000 - // child: ElevatedButton(
1001 - // style: ElevatedButton.styleFrom(
1002 - // backgroundColor: Theme.of(context).highlightColor,
1003 - // ),
1004 - // onPressed: () {
1005 - // final mwebAddress =
1006 - // bitcoin!.getUnusedMwebAddress(dashboardViewModel.wallet);
1007 - // if (mwebAddress == null) return;
1008 - // final paymentRequest =
1009 - // PaymentRequest.fromUri(Uri.parse("litecoin:${mwebAddress}"));
1010 - // Navigator.of(context)
1011 - // .pushNamed(Routes.send, arguments: paymentRequest);
1012 - // },
1013 - // child: Container(
1014 - // color: Colors.transparent,
1015 - // margin: EdgeInsets.all(4),
1016 - // child: Column(
1017 - // mainAxisSize: MainAxisSize.max,
1018 - // crossAxisAlignment: CrossAxisAlignment.center,
1019 - // children: <Widget>[
1020 - // Container(
1021 - // alignment: Alignment.center,
1022 - // decoration: BoxDecoration(shape: BoxShape.circle),
1023 - // child: Image.asset(
1024 - // 'assets/images/received.png',
1025 - // color: Theme.of(context)
1026 - // .extension<BalancePageTheme>()!
1027 - // .balanceAmountColor,
1028 - // width: 64,
1029 - // height: 32,
1030 - // ),
1031 - // ),
1032 - // SizedBox(height: 4),
1033 - // Text(
1034 - // S.of(context).litecoin_mweb_pegin,
1035 - // style: TextStyle(
1036 - // fontSize: 10,
1037 - // color: Theme.of(context)
1038 - // .extension<DashboardPageTheme>()!
1039 - // .cardTextColor),
1040 - // )
1041 - // ],
1042 - // ),
1043 - // ),
1044 - // ),
1045 - // ),
1046 - // ],
1047 - // ),
1048 - ],
1069 + ),
1070 + SizedBox(width: 32),
1071 + Expanded(
1072 + child: Semantics(
1073 + label: S.of(context).litecoin_mweb_pegout,
1074 + child: OutlinedButton(
1075 + onPressed: () {
1076 + final litecoinAddress =
1077 + bitcoin!.getAddress(dashboardViewModel.wallet);
1078 + PaymentRequest? paymentRequest = null;
1079 + if (litecoinAddress.isNotEmpty) {
1080 + paymentRequest = PaymentRequest.fromUri(
1081 + Uri.parse("litecoin:${litecoinAddress}"));
1082 + }
1083 +
1084 + Navigator.pushNamed(
1085 + context,
1086 + Routes.send,
1087 + arguments: {
1088 + 'paymentRequest': paymentRequest,
1089 + 'coinTypeToSpendFrom': UnspentCoinType.mweb,
1090 + },
1091 + );
1092 + },
1093 + style: OutlinedButton.styleFrom(
1094 + backgroundColor: Theme.of(context)
1095 + .extension<SendPageTheme>()!
1096 + .textFieldButtonIconColor
1097 + .withAlpha(50),
1098 + side: BorderSide(color: Colors.grey.shade400, width: 0),
1099 + shape: RoundedRectangleBorder(
1100 + borderRadius: BorderRadius.circular(20),
1101 + ),
1102 + ),
1103 + child: Container(
1104 + padding: EdgeInsets.symmetric(vertical: 12),
1105 + child: Row(
1106 + mainAxisAlignment: MainAxisAlignment.center,
1107 + children: [
1108 + Image.asset(
1109 + height: 30,
1110 + width: 30,
1111 + 'assets/images/upload.png',
1112 + color: Theme.of(context)
1113 + .extension<BalancePageTheme>()!
1114 + .balanceAmountColor,
1115 + ),
1116 + const SizedBox(width: 8),
1117 + Text(
1118 + S.of(context).litecoin_mweb_pegout,
1119 + style: TextStyle(
1120 + color: Theme.of(context)
1121 + .extension<BalancePageTheme>()!
1122 + .assetTitleColor,
1123 + ),
1124 + ),
1125 + ],
1126 + ),
1127 + ),
1128 + ),
1129 + ),
1130 + ),
1131 + ],
1132 + ),
1133 + ),
1134 ),
1135 + SizedBox(height: 16),
1136 ],
1137 ),
1138 ),
lib/src/screens/send/widgets/send_card.dart
+4 -2
@@ -14,7 +14,6 @@ import 'package:cake_wallet/view_model/send/output.dart';
14 import 'package:cw_core/transaction_priority.dart';
15 import 'package:cw_core/wallet_type.dart';
16 import 'package:flutter/material.dart';
17 -import 'package:flutter/services.dart';
17 import 'package:flutter_mobx/flutter_mobx.dart';
18 import 'package:mobx/mobx.dart';
19 import 'package:keyboard_actions/keyboard_actions.dart';
@@ -373,7 +372,10 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
372 padding: EdgeInsets.only(top: 6),
373 child: GestureDetector(
374 key: ValueKey('send_page_unspent_coin_button_key'),
376 - onTap: () => Navigator.of(context).pushNamed(Routes.unspentCoinsList),
375 + onTap: () => Navigator.of(context).pushNamed(
376 + Routes.unspentCoinsList,
377 + arguments: widget.sendViewModel.coinTypeToSpendFrom,
378 + ),
379 child: Container(
380 color: Colors.transparent,
381 child: Row(
lib/view_model/link_view_model.dart
+3 -2
@@ -65,15 +65,16 @@ class LinkViewModel {
65 if (isNanoGptLink) {
66 switch (currentLink?.authority ?? '') {
67 case "exchange":
68 - case "send":
68 return PaymentRequest.fromUri(currentLink);
69 + case "send":
70 + return {"paymentRequest": PaymentRequest.fromUri(currentLink)};
71 case "buy":
72 return true;
73 }
74 }
75
76 if (_isValidPaymentUri) {
76 - return PaymentRequest.fromUri(currentLink);
77 + return {"paymentRequest": PaymentRequest.fromUri(currentLink)};
78 }
79
80 return null;
lib/view_model/send/send_view_model.dart
+20 -5
@@ -20,6 +20,7 @@ import 'package:cake_wallet/wownero/wownero.dart';
20 import 'package:cw_core/exceptions.dart';
21 import 'package:cw_core/transaction_info.dart';
22 import 'package:cw_core/transaction_priority.dart';
23 +import 'package:cw_core/unspent_coin_type.dart';
24 import 'package:cake_wallet/view_model/send/output.dart';
25 import 'package:cake_wallet/view_model/send/send_template_view_model.dart';
26 import 'package:hive/hive.dart';
@@ -67,8 +68,9 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
68 this.balanceViewModel,
69 this.contactListViewModel,
70 this.transactionDescriptionBox,
70 - this.ledgerViewModel,
71 - ) : state = InitialExecutionState(),
71 + this.ledgerViewModel, {
72 + this.coinTypeToSpendFrom = UnspentCoinType.any,
73 + }) : state = InitialExecutionState(),
74 currencies = appStore.wallet!.balance.keys.toList(),
75 selectedCryptoCurrency = appStore.wallet!.currency,
76 hasMultipleTokens = isEVMCompatibleChain(appStore.wallet!.type) ||
@@ -97,6 +99,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
99
100 ObservableList<Output> outputs;
101
102 + final UnspentCoinType coinTypeToSpendFrom;
103 +
104 @action
105 void addOutput() {
106 outputs
@@ -217,7 +221,14 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
221 PendingTransaction? pendingTransaction;
222
223 @computed
220 - String get balance => wallet.balance[selectedCryptoCurrency]!.formattedFullAvailableBalance;
224 + String get balance {
225 + if (coinTypeToSpendFrom == UnspentCoinType.mweb) {
226 + return balanceViewModel.balances.values.first.secondAvailableBalance;
227 + } else if (coinTypeToSpendFrom == UnspentCoinType.nonMweb) {
228 + return balanceViewModel.balances.values.first.availableBalance;
229 + }
230 + return wallet.balance[selectedCryptoCurrency]!.formattedFullAvailableBalance;
231 + }
232
233 @computed
234 bool get isFiatDisabled => balanceViewModel.isFiatDisabled;
@@ -494,8 +505,12 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
505 case WalletType.bitcoin:
506 case WalletType.litecoin:
507 case WalletType.bitcoinCash:
497 - return bitcoin!.createBitcoinTransactionCredentials(outputs,
498 - priority: priority!, feeRate: customBitcoinFeeRate);
508 + return bitcoin!.createBitcoinTransactionCredentials(
509 + outputs,
510 + priority: priority!,
511 + feeRate: customBitcoinFeeRate,
512 + coinTypeToSpendFrom: coinTypeToSpendFrom,
513 + );
514
515 case WalletType.monero:
516 return monero!
lib/view_model/unspent_coins/unspent_coins_list_view_model.dart
+8 -4
@@ -3,6 +3,7 @@ import 'package:cake_wallet/monero/monero.dart';
3 import 'package:cake_wallet/utils/exception_handler.dart';
4 import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_item.dart';
5 import 'package:cake_wallet/wownero/wownero.dart';
6 +import 'package:cw_core/unspent_coin_type.dart';
7 import 'package:cw_core/unspent_coins_info.dart';
8 import 'package:cw_core/unspent_transaction_output.dart';
9 import 'package:cw_core/wallet_base.dart';
@@ -16,9 +17,11 @@ part 'unspent_coins_list_view_model.g.dart';
17 class UnspentCoinsListViewModel = UnspentCoinsListViewModelBase with _$UnspentCoinsListViewModel;
18
19 abstract class UnspentCoinsListViewModelBase with Store {
19 - UnspentCoinsListViewModelBase(
20 - {required this.wallet, required Box<UnspentCoinsInfo> unspentCoinsInfo})
21 - : _unspentCoinsInfo = unspentCoinsInfo,
20 + UnspentCoinsListViewModelBase({
21 + required this.wallet,
22 + required Box<UnspentCoinsInfo> unspentCoinsInfo,
23 + this.coinTypeToSpendFrom = UnspentCoinType.any,
24 + }) : _unspentCoinsInfo = unspentCoinsInfo,
25 _items = ObservableList<UnspentCoinsItem>() {
26 _updateUnspentCoinsInfo();
27 _updateUnspents();
@@ -26,6 +29,7 @@ abstract class UnspentCoinsListViewModelBase with Store {
29
30 WalletBase wallet;
31 final Box<UnspentCoinsInfo> _unspentCoinsInfo;
32 + final UnspentCoinType coinTypeToSpendFrom;
33
34 @observable
35 ObservableList<UnspentCoinsItem> _items;
@@ -103,7 +107,7 @@ abstract class UnspentCoinsListViewModelBase with Store {
107 case WalletType.bitcoin:
108 case WalletType.litecoin:
109 case WalletType.bitcoinCash:
106 - return bitcoin!.getUnspents(wallet);
110 + return bitcoin!.getUnspents(wallet, coinTypeToSpendFrom: coinTypeToSpendFrom);
111 default:
112 return List.empty();
113 }
tool/configure.dart
+4 -6
@@ -87,6 +87,7 @@ import 'package:cw_core/pending_transaction.dart';
87 import 'package:cw_core/receive_page_option.dart';
88 import 'package:cw_core/transaction_info.dart';
89 import 'package:cw_core/transaction_priority.dart';
90 +import 'package:cw_core/unspent_coin_type.dart';
91 import 'package:cw_core/unspent_coins_info.dart';
92 import 'package:cw_core/unspent_transaction_output.dart';
93 import 'package:cw_core/wallet_base.dart';
@@ -94,6 +95,7 @@ import 'package:cw_core/wallet_credentials.dart';
95 import 'package:cw_core/wallet_info.dart';
96 import 'package:cw_core/wallet_service.dart';
97 import 'package:cw_core/wallet_type.dart';
98 +import 'package:cw_core/get_height_by_date.dart';
99 import 'package:hive/hive.dart';
100 import 'package:ledger_flutter/ledger_flutter.dart';
101 import 'package:blockchain_utils/blockchain_utils.dart';
@@ -108,7 +110,6 @@ import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
110 import 'package:cw_bitcoin/bitcoin_receive_page_option.dart';
111 import 'package:cw_bitcoin/bitcoin_wallet.dart';
112 import 'package:cw_bitcoin/electrum_wallet.dart';
111 -import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
113 import 'package:cw_bitcoin/bitcoin_unspent.dart';
114 import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
115 import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
@@ -119,8 +120,6 @@ import 'package:cw_bitcoin/bitcoin_address_record.dart';
120 import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
121 import 'package:cw_bitcoin/litecoin_wallet_service.dart';
122 import 'package:cw_bitcoin/litecoin_wallet.dart';
122 -import 'package:cw_core/get_height_by_date.dart';
123 -import 'package:cw_core/transaction_info.dart';
123 import 'package:cw_bitcoin/bitcoin_hardware_wallet_service.dart';
124 import 'package:mobx/mobx.dart';
125 """;
@@ -166,8 +165,7 @@ abstract class Bitcoin {
165 int getFeeRate(Object wallet, TransactionPriority priority);
166 Future<void> generateNewAddress(Object wallet, String label);
167 Future<void> updateAddress(Object wallet,String address, String label);
169 - Object createBitcoinTransactionCredentials(List<Output> outputs, {required TransactionPriority priority, int? feeRate});
170 - Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs, {TransactionPriority? priority, required int feeRate});
168 + Object createBitcoinTransactionCredentials(List<Output> outputs, {required TransactionPriority priority, int? feeRate, UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any});
169
170 String getAddress(Object wallet);
171 List<ElectrumSubAddress> getSilentPaymentAddresses(Object wallet);
@@ -181,7 +179,7 @@ abstract class Bitcoin {
179 int formatterStringDoubleToBitcoinAmount(String amount);
180 String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate, {int? customRate});
181
184 - List<Unspent> getUnspents(Object wallet);
182 + List<Unspent> getUnspents(Object wallet, {UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any});
183 Future<void> updateUnspents(Object wallet);
184 WalletService createBitcoinWalletService(
185 Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource, bool alwaysScan, bool isDirect);