mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-31 06:55:59 +00:00
Merge branch 'mweb' of https://github.com/cake-tech/cake_wallet into mweb-bg-sync-2
This commit is contained in:
commit
a87a02891f
14 changed files with 180 additions and 90 deletions
4
.github/workflows/pr_test_build_android.yml
vendored
4
.github/workflows/pr_test_build_android.yml
vendored
|
@ -113,15 +113,13 @@ jobs:
|
|||
cd /opt/android/cake_wallet
|
||||
git clone https://github.com/ltcmweb/mwebd
|
||||
cd /opt/android/cake_wallet/mwebd
|
||||
git reset --hard 49c42597ce5036fe1065200c3c056d0aba5f1a58
|
||||
git reset --hard 7f31c84eeb2e954f2c5f385b39db3b8e3b6389e3
|
||||
gomobile bind -target=android -androidapi 21 .
|
||||
mkdir -p /opt/android/cake_wallet/cw_mweb/android/libs/
|
||||
mv ./mwebd.aar $_
|
||||
cd ..
|
||||
rm -rf mwebd
|
||||
|
||||
|
||||
|
||||
- name: Generate KeyStore
|
||||
run: |
|
||||
cd /opt/android/cake_wallet/android/app
|
||||
|
|
3
.github/workflows/pr_test_build_linux.yml
vendored
3
.github/workflows/pr_test_build_linux.yml
vendored
|
@ -99,7 +99,7 @@ jobs:
|
|||
go install golang.org/x/mobile/cmd/gomobile@latest
|
||||
gomobile init
|
||||
|
||||
- name: Build mwebd TODO for linux!
|
||||
- name: Build mwebd
|
||||
run: |
|
||||
# paths are reset after each step, so we need to set them again:
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
|
@ -108,6 +108,7 @@ jobs:
|
|||
cd /opt/android/cake_wallet
|
||||
git clone https://github.com/ltcmweb/mwebd
|
||||
cd /opt/android/cake_wallet/mwebd
|
||||
git reset --hard 7f31c84eeb2e954f2c5f385b39db3b8e3b6389e3
|
||||
gomobile bind -target=android -androidapi 21 .
|
||||
mkdir -p /opt/android/cake_wallet/cw_mweb/android/libs/
|
||||
mv ./mwebd.aar $_
|
||||
|
|
|
@ -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"))) {
|
||||
|
|
|
@ -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<String> getChangeAddress() async {
|
||||
Future<String> getChangeAddress({List<BitcoinOutput>? outputs, UtxoDetails? utxoDetails}) async {
|
||||
updateChangeAddresses();
|
||||
|
||||
if (changeAddresses.isEmpty) {
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import 'package:convert/convert.dart';
|
||||
import 'dart:typed_data';
|
||||
|
||||
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';
|
||||
|
@ -8,8 +12,16 @@ import 'package:cw_mweb/cw_mweb.dart';
|
|||
import 'package:cw_mweb/mwebd.pb.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
// import 'dart:typed_data';
|
||||
// import 'package:bech32/bech32.dart';
|
||||
// import 'package:r_crypto/r_crypto.dart';
|
||||
|
||||
part 'litecoin_wallet_addresses.g.dart';
|
||||
|
||||
String encodeMwebAddress(List<int> scriptPubKey) {
|
||||
return bech32.encode(Bech32("ltcmweb1", scriptPubKey), 250);
|
||||
}
|
||||
|
||||
class LitecoinWalletAddresses = LitecoinWalletAddressesBase with _$LitecoinWalletAddresses;
|
||||
|
||||
abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with Store {
|
||||
|
@ -42,18 +54,15 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
List<String> mwebAddrs = [];
|
||||
|
||||
Future<void> topUpMweb(int index) async {
|
||||
final stub = await CwMweb.stub();
|
||||
// generate up to index + 1000 addresses:
|
||||
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 (mwebAddrs.length == length) {
|
||||
mwebAddrs.addAll(resp.address);
|
||||
}
|
||||
final address = await CwMweb.address(
|
||||
Uint8List.fromList(scanSecret),
|
||||
Uint8List.fromList(spendPubkey),
|
||||
length,
|
||||
);
|
||||
mwebAddrs.add(address!);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +72,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
required Bip32Slip10Secp256k1 hd,
|
||||
BitcoinAddressType? addressType,
|
||||
}) {
|
||||
if (addressType == SegwitAddresType.mweb && mwebEnabled) {
|
||||
if (addressType == SegwitAddresType.mweb) {
|
||||
topUpMweb(index);
|
||||
return hd == sideHd ? mwebAddrs[0] : mwebAddrs[index + 1];
|
||||
}
|
||||
|
@ -76,11 +85,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
required Bip32Slip10Secp256k1 hd,
|
||||
BitcoinAddressType? addressType,
|
||||
}) async {
|
||||
// if mweb isn't enabled we'll just return the regular address type which does effectively nothing
|
||||
// sort of a hack but easier than trying to pull the mweb setting into the electrum_wallet_addresses initialization code
|
||||
// (we want to avoid initializing the mweb.stub() if it's not enabled or we'd be starting the whole server for no reason and it's slow)
|
||||
// TODO: find a way to do address generation without starting the whole mweb server
|
||||
if (addressType == SegwitAddresType.mweb && mwebEnabled) {
|
||||
if (addressType == SegwitAddresType.mweb) {
|
||||
await topUpMweb(index);
|
||||
}
|
||||
return getAddress(index: index, hd: hd, addressType: addressType);
|
||||
|
@ -88,11 +93,38 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
|
||||
@action
|
||||
@override
|
||||
Future<String> getChangeAddress() async {
|
||||
Future<String> getChangeAddress({List<BitcoinOutput>? 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/rafael-xmr/sp_scanner
|
||||
ref: sp_v4.0.0
|
||||
bech32:
|
||||
git:
|
||||
url: https://github.com/cake-tech/bech32.git
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -62,6 +65,7 @@ dependency_overrides:
|
|||
url: https://github.com/cake-tech/bitcoin_base
|
||||
ref: cake-update-v6
|
||||
pointycastle: 3.7.4
|
||||
ffi: 2.1.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
|
|
@ -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)
|
||||
|
@ -40,6 +38,12 @@ class CwMwebPlugin: FlutterPlugin, MethodCallHandler {
|
|||
server = null
|
||||
port = null
|
||||
result.success(null)
|
||||
} else if (call.method == "address") {
|
||||
val scanSecret: ByteArray = call.argument<ByteArray>("scanSecret") ?: ByteArray(0)
|
||||
val spendPub: ByteArray = call.argument<ByteArray>("spendPub") ?: ByteArray(0)
|
||||
val index: Int = call.argument<Int>("index") ?: 0
|
||||
val res = Mwebd.address(scanSecret, spendPub, index)
|
||||
result.success(res)
|
||||
} else {
|
||||
result.notImplemented()
|
||||
}
|
||||
|
|
|
@ -3,70 +3,84 @@ import UIKit
|
|||
import Mwebd
|
||||
|
||||
public class CwMwebPlugin: NSObject, FlutterPlugin {
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let channel = FlutterMethodChannel(name: "cw_mweb", binaryMessenger: registrar.messenger())
|
||||
let instance = CwMwebPlugin()
|
||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||
}
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let channel = FlutterMethodChannel(name: "cw_mweb", binaryMessenger: registrar.messenger())
|
||||
let instance = CwMwebPlugin()
|
||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||
}
|
||||
|
||||
private static var server: MwebdServer?
|
||||
private static var port: Int = 0
|
||||
private static var dataDir: String?
|
||||
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
switch call.method {
|
||||
case "getPlatformVersion":
|
||||
result("iOS " + UIDevice.current.systemVersion)
|
||||
case "start":
|
||||
stopServer()
|
||||
let args = call.arguments as? [String: String]
|
||||
let dataDir = args?["dataDir"]
|
||||
CwMwebPlugin.dataDir = dataDir
|
||||
startServer(result: result)
|
||||
case "stop":
|
||||
stopServer()
|
||||
result(nil)
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
private static var server: MwebdServer?
|
||||
private static var port: Int = 0
|
||||
private static var dataDir: String?
|
||||
|
||||
private func startServer(result: @escaping FlutterResult) {
|
||||
if CwMwebPlugin.server == nil {
|
||||
var error: NSError?
|
||||
CwMwebPlugin.server = MwebdNewServer("", CwMwebPlugin.dataDir, "", &error)
|
||||
|
||||
if let server = CwMwebPlugin.server {
|
||||
do {
|
||||
print("Starting server...")
|
||||
try server.start(0, ret0_: &CwMwebPlugin.port)
|
||||
print("Server started successfully on port: \(CwMwebPlugin.port)")
|
||||
result(CwMwebPlugin.port)
|
||||
} catch let startError as NSError {
|
||||
print("Server Start Error: \(startError.localizedDescription)")
|
||||
result(FlutterError(code: "Server Start Error", message: startError.localizedDescription, details: nil))
|
||||
}
|
||||
} else if let error = error {
|
||||
print("Server Creation Error: \(error.localizedDescription)")
|
||||
result(FlutterError(code: "Server Creation Error", message: error.localizedDescription, details: nil))
|
||||
} else {
|
||||
print("Unknown Error: Failed to create server")
|
||||
result(FlutterError(code: "Unknown Error", message: "Failed to create server", details: nil))
|
||||
}
|
||||
} else {
|
||||
print("Server already running on port: \(CwMwebPlugin.port)")
|
||||
result(CwMwebPlugin.port)
|
||||
}
|
||||
}
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
switch call.method {
|
||||
case "getPlatformVersion":
|
||||
result("iOS " + UIDevice.current.systemVersion)
|
||||
break
|
||||
case "start":
|
||||
stopServer()
|
||||
let args = call.arguments as? [String: String]
|
||||
let dataDir = args?["dataDir"]
|
||||
CwMwebPlugin.dataDir = dataDir
|
||||
startServer(result: result)
|
||||
break
|
||||
case "stop":
|
||||
stopServer()
|
||||
result(nil)
|
||||
break
|
||||
case "address":
|
||||
let args = call.arguments as! [String: Any]
|
||||
let scanSecret = args["scanSecret"] as! FlutterStandardTypedData
|
||||
let spendPub = args["spendPub"] as! FlutterStandardTypedData
|
||||
let index = args["index"] as! Int32
|
||||
|
||||
let scanSecretData = scanSecret.data
|
||||
let spendPubData = spendPub.data
|
||||
result(MwebdAddress(scanSecretData, spendPubData, index))
|
||||
break
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func stopServer() {
|
||||
print("Stopping server")
|
||||
CwMwebPlugin.server?.stop()
|
||||
CwMwebPlugin.server = nil
|
||||
CwMwebPlugin.port = 0
|
||||
}
|
||||
private func startServer(result: @escaping FlutterResult) {
|
||||
if CwMwebPlugin.server == nil {
|
||||
var error: NSError?
|
||||
CwMwebPlugin.server = MwebdNewServer("", CwMwebPlugin.dataDir, "", &error)
|
||||
|
||||
deinit {
|
||||
stopServer()
|
||||
}
|
||||
}
|
||||
if let server = CwMwebPlugin.server {
|
||||
do {
|
||||
print("Starting server...")
|
||||
try server.start(0, ret0_: &CwMwebPlugin.port)
|
||||
print("Server started successfully on port: \(CwMwebPlugin.port)")
|
||||
result(CwMwebPlugin.port)
|
||||
} catch let startError as NSError {
|
||||
print("Server Start Error: \(startError.localizedDescription)")
|
||||
result(FlutterError(code: "Server Start Error", message: startError.localizedDescription, details: nil))
|
||||
}
|
||||
} else if let error = error {
|
||||
print("Server Creation Error: \(error.localizedDescription)")
|
||||
result(FlutterError(code: "Server Creation Error", message: error.localizedDescription, details: nil))
|
||||
} else {
|
||||
print("Unknown Error: Failed to create server")
|
||||
result(FlutterError(code: "Unknown Error", message: "Failed to create server", details: nil))
|
||||
}
|
||||
} else {
|
||||
print("Server already running on port: \(CwMwebPlugin.port)")
|
||||
result(CwMwebPlugin.port)
|
||||
}
|
||||
}
|
||||
|
||||
private func stopServer() {
|
||||
print("Stopping server")
|
||||
CwMwebPlugin.server?.stop()
|
||||
CwMwebPlugin.server = nil
|
||||
CwMwebPlugin.port = 0
|
||||
}
|
||||
|
||||
deinit {
|
||||
stopServer()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:grpc/grpc.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
@ -53,6 +54,15 @@ class CwMweb {
|
|||
await cleanup();
|
||||
}
|
||||
|
||||
static Future<String?> address(Uint8List scanSecret, Uint8List spendPub, int index) async {
|
||||
// try {
|
||||
// return (await CwMwebPlatform.instance.address(scan, spendPub, index))!;
|
||||
// } catch (e) {
|
||||
// print("error generating address!: $e");
|
||||
// }
|
||||
return CwMwebPlatform.instance.address(scanSecret, spendPub, index);
|
||||
}
|
||||
|
||||
static Future<void> cleanup() async {
|
||||
await _clientChannel?.terminate();
|
||||
_rpcClient = null;
|
||||
|
|
|
@ -19,4 +19,14 @@ class MethodChannelCwMweb extends CwMwebPlatform {
|
|||
Future<void> stop() async {
|
||||
await methodChannel.invokeMethod<void>('stop');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> address(Uint8List scanSecret, Uint8List spendPub, int index) async {
|
||||
final result = await methodChannel.invokeMethod<String>('address', {
|
||||
'scanSecret': scanSecret,
|
||||
'spendPub': spendPub,
|
||||
'index': index,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||
|
||||
import 'cw_mweb_method_channel.dart';
|
||||
|
@ -30,4 +32,8 @@ abstract class CwMwebPlatform extends PlatformInterface {
|
|||
Future<void> stop() {
|
||||
throw UnimplementedError('stop() has not been implemented.');
|
||||
}
|
||||
|
||||
Future<String?> address(Uint8List scanSecret, Uint8List spendPub, int index) {
|
||||
throw UnimplementedError('address(int) has not been implemented.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,6 +138,7 @@ dependency_overrides:
|
|||
git:
|
||||
url: https://github.com/cake-tech/bitcoin_base
|
||||
ref: cake-update-v6
|
||||
ffi: 2.1.0
|
||||
|
||||
flutter_icons:
|
||||
image_path: "assets/images/app_logo.png"
|
||||
|
|
|
@ -8,6 +8,7 @@ gomobile init
|
|||
# build mwebd:
|
||||
git clone https://github.com/ltcmweb/mwebd
|
||||
cd mwebd
|
||||
git reset --hard 7f31c84eeb2e954f2c5f385b39db3b8e3b6389e3
|
||||
gomobile bind -target=android -androidapi 21 .
|
||||
mkdir -p ../../../cw_mweb/android/libs/
|
||||
mv ./mwebd.aar $_
|
||||
|
|
|
@ -7,6 +7,7 @@ gomobile init
|
|||
# build mwebd:
|
||||
git clone https://github.com/ltcmweb/mwebd
|
||||
cd mwebd
|
||||
git reset --hard 7f31c84eeb2e954f2c5f385b39db3b8e3b6389e3
|
||||
gomobile bind -target=ios .
|
||||
mv -fn ./Mwebd.xcframework ../../../ios/
|
||||
# cleanup:
|
||||
|
|
Loading…
Reference in a new issue