Mweb fixes ()

* quick fix [still investigating]

* cleaner quick fix

* cleaner quick fix

* log fix

* save to downloads would require an additional permission

* change address handling updates [skip ci]

* should change address not updating

* change address handling updates

* remove unnecessary code + don't reset change address index to 0
This commit is contained in:
Matthew Fosse 2025-01-24 10:09:48 -08:00 committed by GitHub
parent 9673b7c026
commit 199ada3fa9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 55 additions and 60 deletions

View file

@ -2,6 +2,7 @@ import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:blockchain_utils/bip/bip/bip32/bip32.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
import 'package:cw_bitcoin/utils.dart';
import 'package:cw_core/unspent_coin_type.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:mobx/mobx.dart';
@ -26,7 +27,10 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
@override
String getAddress(
{required int index, required Bip32Slip10Secp256k1 hd, BitcoinAddressType? addressType}) {
{required int index,
required Bip32Slip10Secp256k1 hd,
BitcoinAddressType? addressType,
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any}) {
if (addressType == P2pkhAddressType.p2pkh)
return generateP2PKHAddress(hd: hd, index: index, network: network);

View file

@ -842,6 +842,7 @@ abstract class ElectrumWalletBase
final changeAddress = await walletAddresses.getChangeAddress(
inputs: utxoDetails.availableInputs,
outputs: updatedOutputs,
coinTypeToSpendFrom: coinTypeToSpendFrom,
);
final address = RegexUtils.addressTypeFromStr(changeAddress.address, network);
updatedOutputs.add(BitcoinOutput(

View file

@ -4,6 +4,7 @@ import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/electrum_wallet.dart';
import 'package:cw_core/unspent_coin_type.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_bitcoin/bitcoin_unspent.dart';
import 'package:cw_core/wallet_addresses.dart';
@ -47,7 +48,6 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
List<BitcoinAddressRecord>? initialMwebAddresses,
Bip32Slip10Secp256k1? masterHd,
BitcoinAddressType? initialAddressPageType,
}) : _addresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? []).toSet()),
addressesByReceiveType =
ObservableList<BaseBitcoinAddressRecord>.of((<BitcoinAddressRecord>[]).toSet()),
@ -187,13 +187,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
return;
}
try {
final addressRecord = _addresses.firstWhere(
(addressRecord) => addressRecord.address == addr,
);
final addressRecord = _addresses.firstWhere(
(addressRecord) => addressRecord.address == addr,
);
previousAddressRecord = addressRecord;
receiveAddresses.remove(addressRecord);
receiveAddresses.insert(0, addressRecord);
previousAddressRecord = addressRecord;
receiveAddresses.remove(addressRecord);
receiveAddresses.insert(0, addressRecord);
} catch (e) {
printV("ElectrumWalletAddressBase: set address ($addr): $e");
}
@ -274,7 +274,10 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
}
@action
Future<BitcoinAddressRecord> getChangeAddress({List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async {
Future<BitcoinAddressRecord> getChangeAddress(
{List<BitcoinUnspent>? inputs,
List<BitcoinOutput>? outputs,
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any}) async {
updateChangeAddresses();
if (changeAddresses.isEmpty) {

View file

@ -9,6 +9,7 @@ import 'package:crypto/crypto.dart';
import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
import 'package:cw_core/cake_hive.dart';
import 'package:cw_core/mweb_utxo.dart';
import 'package:cw_core/unspent_coin_type.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/node.dart';
import 'package:cw_mweb/mwebd.pbgrpc.dart';
@ -394,7 +395,6 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
// if the confirmations haven't changed, skip updating:
if (tx.confirmations == confirmations) continue;
// if an outgoing tx is now confirmed, delete the utxo from the box (delete the unspent coin):
if (confirmations >= 2 &&
tx.direction == TransactionDirection.outgoing &&
@ -966,10 +966,19 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
List<ECPrivateInfo>? inputPrivKeyInfos,
List<Outpoint>? vinOutpoints,
}) async {
final spendsMweb = utxos.any((utxo) => utxo.utxo.scriptType == SegwitAddresType.mweb);
final paysToMweb = outputs
bool spendsMweb = utxos.any((utxo) => utxo.utxo.scriptType == SegwitAddresType.mweb);
bool paysToMweb = outputs
.any((output) => output.toOutput.scriptPubKey.getAddressType() == SegwitAddresType.mweb);
if (!spendsMweb && !paysToMweb) {
bool isRegular = !spendsMweb && !paysToMweb;
bool isMweb = spendsMweb || paysToMweb;
if (isMweb && !mwebEnabled) {
throw Exception("MWEB is not enabled! can't calculate fee without starting the mweb server!");
// TODO: likely the change address is mweb and just not updated
}
if (isRegular) {
return await super.calcFee(
utxos: utxos,
outputs: outputs,
@ -981,10 +990,6 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
);
}
if (!mwebEnabled) {
throw Exception("MWEB is not enabled! can't calculate fee without starting the mweb server!");
}
if (outputs.length == 1 && outputs[0].toOutput.amount == BigInt.zero) {
outputs = [
BitcoinScriptOutput(
@ -1055,7 +1060,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
if (!mwebEnabled) {
tx.changeAddressOverride =
(await (walletAddresses as LitecoinWalletAddresses).getChangeAddress(isPegIn: false))
(await (walletAddresses as LitecoinWalletAddresses).getChangeAddress(coinTypeToSpendFrom: UnspentCoinType.nonMweb))
.address;
return tx;
}
@ -1103,13 +1108,15 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
}
}
// could probably be simplified but left for clarity:
bool isPegIn = !hasMwebInput && hasMwebOutput;
bool isPegOut = hasMwebInput && hasRegularOutput;
bool isRegular = !hasMwebInput && !hasMwebOutput;
bool shouldNotUseMwebChange = isPegIn || isRegular || !hasMwebInput;
tx.changeAddressOverride = (await (walletAddresses as LitecoinWalletAddresses)
.getChangeAddress(isPegIn: isPegIn || isRegular))
.getChangeAddress(coinTypeToSpendFrom: shouldNotUseMwebChange ? UnspentCoinType.nonMweb : UnspentCoinType.any))
.address;
if (!hasMwebInput && !hasMwebOutput) {
if (isRegular) {
tx.isMweb = false;
return tx;
}
@ -1212,7 +1219,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
}
Future<void> setMwebEnabled(bool enabled) async {
if (mwebEnabled == enabled) {
if (mwebEnabled == enabled &&
alwaysScan == enabled &&
(walletAddresses as LitecoinWalletAddresses).mwebEnabled == enabled) {
return;
}

View file

@ -9,6 +9,7 @@ import 'package:cw_bitcoin/bitcoin_unspent.dart';
import 'package:cw_bitcoin/electrum_wallet.dart';
import 'package:cw_bitcoin/utils.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
import 'package:cw_core/unspent_coin_type.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_mweb/cw_mweb.dart';
@ -148,10 +149,12 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
@action
@override
Future<BitcoinAddressRecord> getChangeAddress(
{List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async {
{List<BitcoinUnspent>? inputs,
List<BitcoinOutput>? outputs,
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any}) async {
// use regular change address on peg in, otherwise use mweb for change address:
if (!mwebEnabled || isPegIn) {
if (!mwebEnabled || coinTypeToSpendFrom == UnspentCoinType.nonMweb) {
return super.getChangeAddress();
}
@ -178,19 +181,17 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
});
bool isPegIn = !comesFromMweb && outputsToMweb;
bool isNonMweb = !comesFromMweb && !outputsToMweb;
if (isPegIn && mwebEnabled) {
return super.getChangeAddress();
}
// use regular change address if it's not an mweb tx:
if (!comesFromMweb && !outputsToMweb) {
// use regular change address if it's not an mweb tx or if it's a peg in:
if (isPegIn || isNonMweb) {
return super.getChangeAddress();
}
}
if (mwebEnabled) {
await ensureMwebAddressUpToIndexExists(1);
updateChangeAddresses();
return BitcoinAddressRecord(
mwebAddrs[0],
index: 0,

View file

@ -77,15 +77,12 @@ class MwebLogsPage extends BasePage {
return AlertWithTwoActions(
alertTitle: S.of(context).export_backup,
alertContent: S.of(context).select_destination,
rightButtonText: S.of(context).save_to_downloads,
leftButtonText: S.of(context).share,
actionRightButton: () async {
const downloadDirPath = "/storage/emulated/0/Download";
final filePath = downloadDirPath + "/debug.log";
await mwebSettingsViewModelBase.saveLogsLocally(filePath);
rightButtonText: S.of(context).save,
leftButtonText: S.of(context).cancel,
actionLeftButton: () async {
Navigator.of(dialogContext).pop();
},
actionLeftButton: () async {
actionRightButton: () async {
Navigator.of(dialogContext).pop();
try {
await share(context);
@ -101,11 +98,8 @@ class MwebLogsPage extends BasePage {
}
Future<void> share(BuildContext context) async {
final filePath = (await getAppDir()).path + "/debug.log";
bool success = await mwebSettingsViewModelBase.saveLogsLocally(filePath);
if (!success) return;
await ShareUtil.shareFile(filePath: filePath, fileName: "debug.log", context: context);
await mwebSettingsViewModelBase.removeLogsLocally(filePath);
final inAppPath = "${(await getApplicationSupportDirectory()).path}/logs/debug.log";
await ShareUtil.shareFile(filePath: inAppPath, fileName: "debug.log", context: context);
}
Future<void> _saveFile() async {

View file

@ -3,6 +3,8 @@ import 'dart:io';
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cw_core/root_dir.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:flutter/widgets.dart';
import 'package:mobx/mobx.dart';
@ -47,25 +49,6 @@ abstract class MwebSettingsViewModelBase with Store {
_settingsStore.mwebAlwaysScan = value;
}
Future<bool> saveLogsLocally(String filePath) async {
try {
final appSupportPath = (await getApplicationSupportDirectory()).path;
final logsFile = File("$appSupportPath/logs/debug.log");
if (!logsFile.existsSync()) {
throw Exception('Logs file does not exist');
}
await logsFile.copy(filePath);
return true;
} catch (e, s) {
ExceptionHandler.onError(FlutterErrorDetails(
exception: e,
stack: s,
library: "Export Logs",
));
return false;
}
}
Future<String> getAbbreviatedLogs() async {
final appSupportPath = (await getApplicationSupportDirectory()).path;
final logsFile = File("$appSupportPath/logs/debug.log");