diff --git a/cw_bitcoin/lib/litecoin_wallet_addresses.dart b/cw_bitcoin/lib/litecoin_wallet_addresses.dart index 49ca81476..c0940ca5d 100644 --- a/cw_bitcoin/lib/litecoin_wallet_addresses.dart +++ b/cw_bitcoin/lib/litecoin_wallet_addresses.dart @@ -1,4 +1,6 @@ +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/utils.dart'; import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; @@ -7,88 +9,91 @@ 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'; +// import 'dart:typed_data'; +// import 'package:bech32/bech32.dart'; +// import 'package:r_crypto/r_crypto.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'; -class Keychain { - final ECPrivate scan; - ECPrivate? spend; - ECPublic? spendPubKey; +// ECPrivate mi(int index) { +// final input = BytesBuilder(); +// // Write HashTagAddress to the input +// input.addByte(HashTagAddress.codeUnitAt(0)); - Keychain({required this.scan, this.spend, this.spendPubKey}) { - if (this.spend != null) { - spendPubKey = this.spend!.getPublic(); - } - } +// // 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); - static const HashTagAddress = 'A'; +// // Hash the input using Blake3 with a length of 32 bytes +// final hash = rHash.hashString(HashType.blake3(length: 32), input.toString()); - ECPrivate mi(int index) { - final input = BytesBuilder(); +// // Return the hash digest +// var res = Uint8List.fromList(hash); +// return ECPrivate.fromBytes(res); +// } - // Write HashTagAddress to the input - input.addByte(HashTagAddress.codeUnitAt(0)); +// Keychain address(int index) { - // 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); +// 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()); - // Write scan to the input - input.add(scan.prive.raw); +// // 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()); - // Hash the input using Blake3 with a length of 32 bytes - final hash = rHash.hashString(HashType.blake3(length: 32), input.toString()); +// return Keychain(scan: AiPriv, spend: BiPriv); +// } - // Return the hash digest - var res = Uint8List.fromList(hash); - return ECPrivate.fromBytes(res); - } +// String addressString(int index) { +// final address = this.address(index); +// List bytes = []; +// bytes.addAll(address.scan.toBytes()); +// bytes.addAll(address.spend!.toBytes()); +// return encodeMwebAddress(bytes); +// } - Keychain address(int index) { +// // 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); +// // } - final miPub = this.mi(index).getPublic(); - final Bi = spendPubKey!.pubkeyAdd(miPub); - final Ai = Bi.pubkeyMult(ECPublic.fromBytes(scan.toBytes())); - // 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()); +// String encodeMwebAddress(List scriptPubKey) { +// return bech32.encode(Bech32("ltcmweb", scriptPubKey)); +// } +// } - 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); } - class LitecoinWalletAddresses = LitecoinWalletAddressesBase with _$LitecoinWalletAddresses; + abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with Store { LitecoinWalletAddressesBase( WalletInfo walletInfo, { @@ -119,7 +124,6 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with List mwebAddrs = []; List oldMwebAddrs = []; - Future topUpMweb(int index) async { final stub = await CwMweb.stub(); while (oldMwebAddrs.length - index < 1000) { @@ -135,16 +139,19 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with } } - - Keychain k = Keychain(scan: ECPrivate.fromBytes(scanSecret), spendPubKey: ECPublic.fromBytes(spendPubkey),); - + // 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 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}"); - } @override 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 b1180dd4a..228725ef1 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 @@ -40,6 +40,12 @@ class CwMwebPlugin: FlutterPlugin, MethodCallHandler { server = null port = null result.success(null) + } else if (call.method == "address") { + 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) + result.success(res) } else { result.notImplemented() } diff --git a/cw_mweb/ios/Classes/CwMwebPlugin.swift b/cw_mweb/ios/Classes/CwMwebPlugin.swift index ed08d6748..e68344a4b 100644 --- a/cw_mweb/ios/Classes/CwMwebPlugin.swift +++ b/cw_mweb/ios/Classes/CwMwebPlugin.swift @@ -3,70 +3,90 @@ 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: String] + let scanSecret = args?["scanSecret"] + let spendPub = args?["spendPub"] + let index = args?["index"] + result(address(scanSecret, spendPub, 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 + } + + private func address(_ scanSecret: String?, _ spendPub: String?, _ index: Int?) -> String? { + guard let scanSecret = scanSecret, let spendPub = spendPub, let index = index else { + print("Invalid arguments for address function") + return nil + } + + return MwebdAddressIndex(scanSecret, spendPub, UInt32(index)) + } + + deinit { + stopServer() + } } \ No newline at end of file diff --git a/cw_mweb/lib/cw_mweb.dart b/cw_mweb/lib/cw_mweb.dart index df3300379..46ae512a0 100644 --- a/cw_mweb/lib/cw_mweb.dart +++ b/cw_mweb/lib/cw_mweb.dart @@ -53,6 +53,15 @@ class CwMweb { await cleanup(); } + static Future address(String scanSecret, String 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 cleanup() async { await _clientChannel?.terminate(); _rpcClient = null; diff --git a/cw_mweb/lib/cw_mweb_method_channel.dart b/cw_mweb/lib/cw_mweb_method_channel.dart index 9451db310..6f7ad2279 100644 --- a/cw_mweb/lib/cw_mweb_method_channel.dart +++ b/cw_mweb/lib/cw_mweb_method_channel.dart @@ -19,4 +19,14 @@ class MethodChannelCwMweb extends CwMwebPlatform { Future stop() async { await methodChannel.invokeMethod('stop'); } + + @override + Future address(String scanSecret, String spendPub, int index) async { + final result = await methodChannel.invokeMethod('address', { + 'scanSecret': scanSecret, + 'spendPub': spendPub, + 'index': index, + }); + return result; + } } diff --git a/cw_mweb/lib/cw_mweb_platform_interface.dart b/cw_mweb/lib/cw_mweb_platform_interface.dart index a5a46adbc..a63319341 100644 --- a/cw_mweb/lib/cw_mweb_platform_interface.dart +++ b/cw_mweb/lib/cw_mweb_platform_interface.dart @@ -30,4 +30,8 @@ abstract class CwMwebPlatform extends PlatformInterface { Future stop() { throw UnimplementedError('stop() has not been implemented.'); } + + Future address(String scanSecret, String spendPub, int index) { + throw UnimplementedError('address(int) has not been implemented.'); + } } diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 6e07b989b..f05654009 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -136,6 +136,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"