CW-994 mweb enhancements (#2204)
* add mweb block explorer * potential fix for #2 * fix spending when mweb is disabled * Update cw_bitcoin/lib/litecoin_wallet.dart * fix resolving conflict missing brackets --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
Matthew Fosse committed
Dec 1, 2025 at 18:16 UTC
20022c03930d6764279babcfcc433ddf219ab759
4 files changed
+54
-7
cw_bitcoin/lib/electrum_wallet.dart
+7
-1
@@ -11,7 +11,6 @@ import 'package:cw_bitcoin/bitcoin_amount_format.dart';
11
import 'package:cw_core/utils/print_verbose.dart';
12
import 'package:cw_bitcoin/bitcoin_wallet.dart';
13
import 'package:cw_bitcoin/litecoin_wallet.dart';
14
-import 'package:path_provider/path_provider.dart';
14
import 'package:shared_preferences/shared_preferences.dart';
15
import 'package:blockchain_utils/blockchain_utils.dart';
16
import 'package:collection/collection.dart';
@@ -899,6 +898,13 @@ abstract class ElectrumWalletBase
898
throw BitcoinTransactionNoDustException();
899
}
900
901
+ // if mweb isn't enabled, don't consider spending mweb coins:
902
+ if (this is LitecoinWallet) {
903
+ var mwebEnabled = (this as LitecoinWallet).mwebEnabled;
904
+ if (!mwebEnabled) {
905
+ coinTypeToSpendFrom = UnspentCoinType.nonMweb;
906
+ }
907
+ }
908
909
// If there is only one output, and the amount to send is more than the max spendable amount
910
// then it is actually a send all transaction
cw_bitcoin/lib/litecoin_wallet.dart
+21
-5
@@ -886,6 +886,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
886
if (unspent.vout == 0) {
887
unspent.isChange = true;
888
}
889
+
890
+ // printV("unspent: $unspent ${unspent.vout} ${utxo.value}");
891
mwebUnspentCoins.add(unspent);
892
});
893
@@ -1140,13 +1142,27 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
1142
@override
1143
Future<PendingTransaction> createTransaction(Object credentials) async {
1144
try {
1143
- var tx = await super.createTransaction(credentials) as PendingBitcoinTransaction;
1145
+ var creds;
1146
+ if (!mwebEnabled) {
1147
+ BitcoinTransactionCredentials btcCreds = (credentials as BitcoinTransactionCredentials);
1148
+ // sets unspent coin type to nonMweb:
1149
+ creds = BitcoinTransactionCredentials(
1150
+ btcCreds.outputs,
1151
+ priority: btcCreds.priority,
1152
+ feeRate: btcCreds.feeRate,
1153
+ coinTypeToSpendFrom: UnspentCoinType.nonMweb,
1154
+ );
1155
+ } else {
1156
+ creds = credentials;
1157
+ }
1158
+ var tx = await super.createTransaction(creds as Object) as PendingBitcoinTransaction;
1159
tx.isMweb = mwebEnabled;
1160
1161
if (!mwebEnabled) {
1162
tx.changeAddressOverride = (await (walletAddresses as LitecoinWalletAddresses)
1163
.getChangeAddress(coinTypeToSpendFrom: UnspentCoinType.nonMweb))
1164
.address;
1165
+
1166
if (tx.shouldCommitUR()) {
1167
tx.unsignedPsbt = await buildPsbt(tx, false);
1168
}
@@ -1165,17 +1181,17 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
1181
final address = output.address.toLowerCase();
1182
final extractedAddress = output.extractedAddress?.toLowerCase();
1183
1168
- if (address.contains("mweb")) {
1184
+ if (address.startsWith("ltcmweb")) {
1185
hasMwebOutput = true;
1186
}
1171
- if (!address.contains("mweb")) {
1187
+ if (!address.startsWith("ltcmweb")) {
1188
hasRegularOutput = true;
1189
}
1190
if (extractedAddress != null && extractedAddress.isNotEmpty) {
1175
- if (extractedAddress.contains("mweb")) {
1191
+ if (extractedAddress.startsWith("ltcmweb")) {
1192
hasMwebOutput = true;
1193
}
1178
- if (!extractedAddress.contains("mweb")) {
1194
+ if (!extractedAddress.startsWith("ltcmweb")) {
1195
hasRegularOutput = true;
1196
}
1197
}
cw_bitcoin/lib/litecoin_wallet_addresses.dart
+1
-1
@@ -188,7 +188,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
188
if (!element.isSending || element.isFrozen) {
189
return;
190
}
191
- if (element.address.contains("mweb")) {
191
+ if (element.address.startsWith("ltcmweb")) {
192
comesFromMweb = true;
193
}
194
});
lib/view_model/transaction_details_view_model.dart
+25
@@ -59,6 +59,7 @@ abstract class TransactionDetailsViewModelBase with Store {
59
if (!canReplaceByFee) _checkForRBF(tx);
60
break;
61
case WalletType.litecoin:
62
+ _addLitecoinListItems(tx, dateFormat);
63
case WalletType.bitcoinCash:
64
_addElectrumListItems(tx, dateFormat);
65
break;
@@ -388,6 +389,30 @@ abstract class TransactionDetailsViewModelBase with Store {
389
items.addAll(_items);
390
}
391
392
+ void _addLitecoinListItems(TransactionInfo tx, DateFormat dateFormat) {
393
+ _addElectrumListItems(tx, dateFormat);
394
+
395
+ bool isMweb = bitcoin!.txIsMweb(tx);
396
+
397
+ final _items = [
398
+ if (isMweb)
399
+ BlockExplorerListItem(
400
+ title: S.current.view_in_block_explorer,
401
+ value: S.current.view_transaction_on + 'mwebexplorer.com',
402
+ onTap: () async {
403
+ try {
404
+ final uri = Uri.parse('https://www.mwebexplorer.com/blocks/block/${tx.height}');
405
+ if (await canLaunchUrl(uri))
406
+ await launchUrl(uri, mode: LaunchMode.externalApplication);
407
+ } catch (e) {}
408
+ },
409
+ key: ValueKey('block_explorer_list_item_mweb_wallet_type_key'),
410
+ ),
411
+ ];
412
+
413
+ items.addAll(_items);
414
+ }
415
+
416
void _addHavenListItems(TransactionInfo tx, DateFormat dateFormat) {
417
items.addAll([
418
StandartListItem(