diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 521384e53..ea99c6cd8 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'dart:isolate'; import 'package:bitcoin_base/bitcoin_base.dart'; +import 'package:cw_bitcoin/litecoin_wallet_addresses.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:cw_core/encryption_file_utils.dart'; import 'package:blockchain_utils/blockchain_utils.dart'; @@ -795,7 +796,10 @@ abstract class ElectrumWalletBase throw BitcoinTransactionWrongBalanceException(); } - final changeAddress = await walletAddresses.getChangeAddress(); + final changeAddress = await walletAddresses.getChangeAddress( + outputs: outputs, + utxoDetails: utxoDetails, + ); final address = addressTypeFromStr(changeAddress, network); outputs.add(BitcoinOutput( address: address, @@ -2061,7 +2065,8 @@ abstract class ElectrumWalletBase _isTryingToConnect = true; Timer(Duration(seconds: 10), () { - if (this.syncStatus is NotConnectedSyncStatus || this.syncStatus is LostConnectionSyncStatus) { + if (this.syncStatus is NotConnectedSyncStatus || + this.syncStatus is LostConnectionSyncStatus) { this.electrumClient.connectToUri( node!.uri, useSSL: node!.useSSL ?? false, @@ -2387,6 +2392,8 @@ class PublicKeyWithDerivationPath { } BitcoinBaseAddress addressTypeFromStr(String address, BasedUtxoNetwork network) { + // print("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + // print(network); if (network is BitcoinCashNetwork) { if (!address.startsWith("bitcoincash:") && (address.startsWith("q") || address.startsWith("p"))) { diff --git a/cw_bitcoin/lib/electrum_wallet_addresses.dart b/cw_bitcoin/lib/electrum_wallet_addresses.dart index 388b3d468..e442a03e8 100644 --- a/cw_bitcoin/lib/electrum_wallet_addresses.dart +++ b/cw_bitcoin/lib/electrum_wallet_addresses.dart @@ -1,6 +1,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/wallet_addresses.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_type.dart'; @@ -239,7 +240,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } @action - Future getChangeAddress() async { + Future getChangeAddress({List? outputs, UtxoDetails? utxoDetails}) async { updateChangeAddresses(); if (changeAddresses.isEmpty) { diff --git a/cw_bitcoin/lib/litecoin_wallet_addresses.dart b/cw_bitcoin/lib/litecoin_wallet_addresses.dart index c0940ca5d..ed321841e 100644 --- a/cw_bitcoin/lib/litecoin_wallet_addresses.dart +++ b/cw_bitcoin/lib/litecoin_wallet_addresses.dart @@ -2,6 +2,7 @@ import 'package:bech32/bech32.dart'; import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:blockchain_utils/bech32/bech32_base.dart'; import 'package:blockchain_utils/blockchain_utils.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/wallet_info.dart'; @@ -15,79 +16,6 @@ import 'package:mobx/mobx.dart'; part 'litecoin_wallet_addresses.g.dart'; -// class Keychain { -// // ECPrivate scan; -// // ECPrivate? spend; -// ECPrivate scan; -// ECPrivate? spend; -// ECPublic? spendPubKey; - -// Keychain({required this.scan, this.spend, this.spendPubKey}) { -// if (this.spend != null) { -// spendPubKey = this.spend!.getPublic(); -// } -// } - -// static const HashTagAddress = 'A'; - -// ECPrivate mi(int index) { -// final input = BytesBuilder(); - -// // Write HashTagAddress to the input -// input.addByte(HashTagAddress.codeUnitAt(0)); - -// // Write index to the input in little endian -// final indexBytes = Uint8List(4); -// final byteData = ByteData.view(indexBytes.buffer); -// byteData.setUint32(0, index, Endian.little); -// input.add(indexBytes); - -// // Write scan to the input -// input.add(scan.prive.raw); - -// // Hash the input using Blake3 with a length of 32 bytes -// final hash = rHash.hashString(HashType.blake3(length: 32), input.toString()); - -// // Return the hash digest -// var res = Uint8List.fromList(hash); -// return ECPrivate.fromBytes(res); -// } - -// Keychain address(int index) { - -// final miPub = this.mi(index).getPublic(); -// final Bi = spendPubKey!.pubkeyAdd(miPub); -// // final Ai = Bi.pubkeyMult(ECPublic.fromBytes(scan.toBytes())); -// final Ai = Bi.tweakMul(scan.toBigInt()); - -// // final miPubKey = ECCurve_secp256k1().G * BigInt.parse(hex.encode(mi), radix: 16); -// // final Bi = spendPubKey + miPubKey; -// // return Uint8List.fromList(Ai.getEncoded(compressed: true) + Bi.getEncoded(compressed: true)); -// final AiPriv = ECPrivate.fromBytes(Ai.toBytes()); -// final BiPriv = ECPrivate.fromBytes(Bi.toBytes()); - -// return Keychain(scan: AiPriv, spend: BiPriv); -// } - -// String addressString(int index) { -// final address = this.address(index); -// List bytes = []; -// bytes.addAll(address.scan.toBytes()); -// bytes.addAll(address.spend!.toBytes()); -// return encodeMwebAddress(bytes); -// } - -// // Uint8List spendKey(int index) { -// // final mi = this.mi(index); -// // final spendKey = spend + ECCurve_secp256k1().G * BigInt.parse(hex.encode(mi), radix: 16); -// // return spendKey.getEncoded(compressed: true); -// // } - -// String encodeMwebAddress(List scriptPubKey) { -// return bech32.encode(Bech32("ltcmweb", scriptPubKey)); -// } -// } - String encodeMwebAddress(List scriptPubKey) { return bech32.encode(Bech32("ltcmweb1", scriptPubKey), 250); } @@ -126,32 +54,28 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with Future topUpMweb(int index) async { final stub = await CwMweb.stub(); - while (oldMwebAddrs.length - index < 1000) { - final length = oldMwebAddrs.length; + while (mwebAddrs.length - index < 1000) { + final length = mwebAddrs.length; final resp = await stub.addresses(AddressRequest( fromIndex: length, toIndex: index + 1000, scanSecret: scanSecret, spendPubkey: spendPubkey, )); - if (oldMwebAddrs.length == length) { - oldMwebAddrs.addAll(resp.address); + if (mwebAddrs.length == length) { + mwebAddrs.addAll(resp.address); } } - // Keychain k = Keychain(scan: ECPrivate.fromBytes(scanSecret), spendPubKey: ECPublic.fromBytes(spendPubkey),); - - for (int i = 0; i < 10; i++) { - // final address = k.addressString(i + 1000); - final addressHex = - await CwMweb.address(hex.encode(scanSecret), hex.encode(spendPubkey), index); - // print(addressHex); - // print(hex.decode(addressHex!).length); - // return; - final address = encodeMwebAddress(hex.decode(addressHex!)); - mwebAddrs.add(address); - } - print("old function: ${oldMwebAddrs.first} new function!: ${mwebAddrs.first}"); + // for (int i = 0; i < 10; i++) { + // final address = await CwMweb.address( + // hex.encode(scanSecret), + // hex.encode(spendPubkey), + // index + 1000, + // ); + // mwebAddrs.add(address!); + // } + // print("old function: ${oldMwebAddrs.first} new function!: ${mwebAddrs.first}"); } @override @@ -185,11 +109,38 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with @action @override - Future getChangeAddress() async { + Future getChangeAddress({List? outputs, UtxoDetails? utxoDetails}) async { + // use regular change address on peg in, otherwise use mweb for change address: + + if (outputs != null && utxoDetails != null) { + // check if this is a PEGIN: + bool outputsToMweb = false; + bool comesFromMweb = false; + + for (var i = 0; i < outputs.length; i++) { + // TODO: probably not the best way to tell if this is an mweb address + // (but it doesn't contain the "mweb" text at this stage) + if (outputs[i].address.toAddress(network).length > 110) { + outputsToMweb = true; + } + } + utxoDetails.availableInputs.forEach((element) { + if (element.address.contains("mweb")) { + comesFromMweb = true; + } + }); + + bool isPegIn = !comesFromMweb && outputsToMweb; + if (isPegIn && mwebEnabled) { + return super.getChangeAddress(); + } + } + if (mwebEnabled) { await topUpMweb(0); return mwebAddrs[0]; } + return super.getChangeAddress(); } } diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index b121a9538..8588969c4 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -44,7 +44,6 @@ dependencies: bech32: git: url: https://github.com/cake-tech/bech32.git - r_crypto: ^0.5.0 dev_dependencies: flutter_test: diff --git a/cw_mweb/android/src/main/kotlin/com/cakewallet/mweb/CwMwebPlugin.kt b/cw_mweb/android/src/main/kotlin/com/cakewallet/mweb/CwMwebPlugin.kt index 228725ef1..fea382487 100644 --- a/cw_mweb/android/src/main/kotlin/com/cakewallet/mweb/CwMwebPlugin.kt +++ b/cw_mweb/android/src/main/kotlin/com/cakewallet/mweb/CwMwebPlugin.kt @@ -30,8 +30,6 @@ class CwMwebPlugin: FlutterPlugin, MethodCallHandler { if (call.method == "start") { server?.stop() val dataDir = call.argument("dataDir") ?: "" - // server = server ?: Mwebd.newServer("", dataDir, "") - // port = port ?: server?.start(0) server = server ?: Mwebd.newServer("", dataDir, "") port = server?.start(0) result.success(port) @@ -44,7 +42,7 @@ class CwMwebPlugin: FlutterPlugin, MethodCallHandler { val scanSecret: String = call.argument("scanSecret") ?: "" val spendPub: String = call.argument("spendPub") ?: "" val index: Int = call.argument("index") ?: 0 - val res = Mwebd.addressIndex(scanSecret, spendPub) + val res = Mwebd.addressIndex(scanSecret, spendPub, index.toString()) result.success(res) } else { result.notImplemented()