mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-31 15:06:04 +00:00
wip
This commit is contained in:
parent
5ec0e264ce
commit
7b5c36e5a7
7 changed files with 185 additions and 128 deletions
|
@ -1,4 +1,6 @@
|
||||||
|
import 'package:bech32/bech32.dart';
|
||||||
import 'package:bitcoin_base/bitcoin_base.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:blockchain_utils/blockchain_utils.dart';
|
||||||
import 'package:cw_bitcoin/utils.dart';
|
import 'package:cw_bitcoin/utils.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_addresses.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:cw_mweb/mwebd.pb.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
import 'dart:typed_data';
|
// import 'dart:typed_data';
|
||||||
import 'package:bech32/bech32.dart';
|
// import 'package:bech32/bech32.dart';
|
||||||
import 'package:r_crypto/r_crypto.dart';
|
// import 'package:r_crypto/r_crypto.dart';
|
||||||
|
|
||||||
part 'litecoin_wallet_addresses.g.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 {
|
// ECPrivate mi(int index) {
|
||||||
final ECPrivate scan;
|
// final input = BytesBuilder();
|
||||||
ECPrivate? spend;
|
|
||||||
ECPublic? spendPubKey;
|
|
||||||
|
|
||||||
|
// // Write HashTagAddress to the input
|
||||||
|
// input.addByte(HashTagAddress.codeUnitAt(0));
|
||||||
|
|
||||||
Keychain({required this.scan, this.spend, this.spendPubKey}) {
|
// // Write index to the input in little endian
|
||||||
if (this.spend != null) {
|
// final indexBytes = Uint8List(4);
|
||||||
spendPubKey = this.spend!.getPublic();
|
// 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) {
|
// // Return the hash digest
|
||||||
final input = BytesBuilder();
|
// var res = Uint8List.fromList(hash);
|
||||||
|
// return ECPrivate.fromBytes(res);
|
||||||
|
// }
|
||||||
|
|
||||||
// Write HashTagAddress to the input
|
// Keychain address(int index) {
|
||||||
input.addByte(HashTagAddress.codeUnitAt(0));
|
|
||||||
|
|
||||||
// Write index to the input in little endian
|
// final miPub = this.mi(index).getPublic();
|
||||||
final indexBytes = Uint8List(4);
|
// final Bi = spendPubKey!.pubkeyAdd(miPub);
|
||||||
final byteData = ByteData.view(indexBytes.buffer);
|
// // final Ai = Bi.pubkeyMult(ECPublic.fromBytes(scan.toBytes()));
|
||||||
byteData.setUint32(0, index, Endian.little);
|
// final Ai = Bi.tweakMul(scan.toBigInt());
|
||||||
input.add(indexBytes);
|
|
||||||
|
|
||||||
// Write scan to the input
|
// // final miPubKey = ECCurve_secp256k1().G * BigInt.parse(hex.encode(mi), radix: 16);
|
||||||
input.add(scan.prive.raw);
|
// // 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
|
// return Keychain(scan: AiPriv, spend: BiPriv);
|
||||||
final hash = rHash.hashString(HashType.blake3(length: 32), input.toString());
|
// }
|
||||||
|
|
||||||
// Return the hash digest
|
// String addressString(int index) {
|
||||||
var res = Uint8List.fromList(hash);
|
// final address = this.address(index);
|
||||||
return ECPrivate.fromBytes(res);
|
// List<int> 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();
|
// String encodeMwebAddress(List<int> scriptPubKey) {
|
||||||
final Bi = spendPubKey!.pubkeyAdd(miPub);
|
// return bech32.encode(Bech32("ltcmweb", scriptPubKey));
|
||||||
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());
|
|
||||||
|
|
||||||
return Keychain(scan: AiPriv, spend: BiPriv);
|
String encodeMwebAddress(List<int> scriptPubKey) {
|
||||||
}
|
return bech32.encode(Bech32("ltcmweb1", scriptPubKey), 250);
|
||||||
|
|
||||||
String addressString(int index) {
|
|
||||||
final address = this.address(index);
|
|
||||||
List<int> 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<int> scriptPubKey) {
|
|
||||||
return bech32.encode(Bech32("ltcmweb", scriptPubKey));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class LitecoinWalletAddresses = LitecoinWalletAddressesBase with _$LitecoinWalletAddresses;
|
class LitecoinWalletAddresses = LitecoinWalletAddressesBase with _$LitecoinWalletAddresses;
|
||||||
|
|
||||||
abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with Store {
|
abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with Store {
|
||||||
LitecoinWalletAddressesBase(
|
LitecoinWalletAddressesBase(
|
||||||
WalletInfo walletInfo, {
|
WalletInfo walletInfo, {
|
||||||
|
@ -119,7 +124,6 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
||||||
List<String> mwebAddrs = [];
|
List<String> mwebAddrs = [];
|
||||||
List<String> oldMwebAddrs = [];
|
List<String> oldMwebAddrs = [];
|
||||||
|
|
||||||
|
|
||||||
Future<void> topUpMweb(int index) async {
|
Future<void> topUpMweb(int index) async {
|
||||||
final stub = await CwMweb.stub();
|
final stub = await CwMweb.stub();
|
||||||
while (oldMwebAddrs.length - index < 1000) {
|
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++) {
|
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);
|
mwebAddrs.add(address);
|
||||||
}
|
}
|
||||||
print("old function: ${oldMwebAddrs.first} new function!: ${mwebAddrs.first}");
|
print("old function: ${oldMwebAddrs.first} new function!: ${mwebAddrs.first}");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -40,6 +40,12 @@ class CwMwebPlugin: FlutterPlugin, MethodCallHandler {
|
||||||
server = null
|
server = null
|
||||||
port = null
|
port = null
|
||||||
result.success(null)
|
result.success(null)
|
||||||
|
} else if (call.method == "address") {
|
||||||
|
val scanSecret: String = call.argument<String>("scanSecret") ?: ""
|
||||||
|
val spendPub: String = call.argument<String>("spendPub") ?: ""
|
||||||
|
val index: Int = call.argument<Int>("index") ?: 0
|
||||||
|
val res = Mwebd.addressIndex(scanSecret, spendPub)
|
||||||
|
result.success(res)
|
||||||
} else {
|
} else {
|
||||||
result.notImplemented()
|
result.notImplemented()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,70 +3,90 @@ import UIKit
|
||||||
import Mwebd
|
import Mwebd
|
||||||
|
|
||||||
public class CwMwebPlugin: NSObject, FlutterPlugin {
|
public class CwMwebPlugin: NSObject, FlutterPlugin {
|
||||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||||
let channel = FlutterMethodChannel(name: "cw_mweb", binaryMessenger: registrar.messenger())
|
let channel = FlutterMethodChannel(name: "cw_mweb", binaryMessenger: registrar.messenger())
|
||||||
let instance = CwMwebPlugin()
|
let instance = CwMwebPlugin()
|
||||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static var server: MwebdServer?
|
private static var server: MwebdServer?
|
||||||
private static var port: Int = 0
|
private static var port: Int = 0
|
||||||
private static var dataDir: String?
|
private static var dataDir: String?
|
||||||
|
|
||||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||||
switch call.method {
|
switch call.method {
|
||||||
case "getPlatformVersion":
|
case "getPlatformVersion":
|
||||||
result("iOS " + UIDevice.current.systemVersion)
|
result("iOS " + UIDevice.current.systemVersion)
|
||||||
case "start":
|
break
|
||||||
stopServer()
|
case "start":
|
||||||
let args = call.arguments as? [String: String]
|
stopServer()
|
||||||
let dataDir = args?["dataDir"]
|
let args = call.arguments as? [String: String]
|
||||||
CwMwebPlugin.dataDir = dataDir
|
let dataDir = args?["dataDir"]
|
||||||
startServer(result: result)
|
CwMwebPlugin.dataDir = dataDir
|
||||||
case "stop":
|
startServer(result: result)
|
||||||
stopServer()
|
break
|
||||||
result(nil)
|
case "stop":
|
||||||
default:
|
stopServer()
|
||||||
result(FlutterMethodNotImplemented)
|
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 startServer(result: @escaping FlutterResult) {
|
private func startServer(result: @escaping FlutterResult) {
|
||||||
if CwMwebPlugin.server == nil {
|
if CwMwebPlugin.server == nil {
|
||||||
var error: NSError?
|
var error: NSError?
|
||||||
CwMwebPlugin.server = MwebdNewServer("", CwMwebPlugin.dataDir, "", &error)
|
CwMwebPlugin.server = MwebdNewServer("", CwMwebPlugin.dataDir, "", &error)
|
||||||
|
|
||||||
if let server = CwMwebPlugin.server {
|
if let server = CwMwebPlugin.server {
|
||||||
do {
|
do {
|
||||||
print("Starting server...")
|
print("Starting server...")
|
||||||
try server.start(0, ret0_: &CwMwebPlugin.port)
|
try server.start(0, ret0_: &CwMwebPlugin.port)
|
||||||
print("Server started successfully on port: \(CwMwebPlugin.port)")
|
print("Server started successfully on port: \(CwMwebPlugin.port)")
|
||||||
result(CwMwebPlugin.port)
|
result(CwMwebPlugin.port)
|
||||||
} catch let startError as NSError {
|
} catch let startError as NSError {
|
||||||
print("Server Start Error: \(startError.localizedDescription)")
|
print("Server Start Error: \(startError.localizedDescription)")
|
||||||
result(FlutterError(code: "Server Start Error", message: startError.localizedDescription, details: nil))
|
result(FlutterError(code: "Server Start Error", message: startError.localizedDescription, details: nil))
|
||||||
}
|
}
|
||||||
} else if let error = error {
|
} else if let error = error {
|
||||||
print("Server Creation Error: \(error.localizedDescription)")
|
print("Server Creation Error: \(error.localizedDescription)")
|
||||||
result(FlutterError(code: "Server Creation Error", message: error.localizedDescription, details: nil))
|
result(FlutterError(code: "Server Creation Error", message: error.localizedDescription, details: nil))
|
||||||
} else {
|
} else {
|
||||||
print("Unknown Error: Failed to create server")
|
print("Unknown Error: Failed to create server")
|
||||||
result(FlutterError(code: "Unknown Error", message: "Failed to create server", details: nil))
|
result(FlutterError(code: "Unknown Error", message: "Failed to create server", details: nil))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print("Server already running on port: \(CwMwebPlugin.port)")
|
print("Server already running on port: \(CwMwebPlugin.port)")
|
||||||
result(CwMwebPlugin.port)
|
result(CwMwebPlugin.port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func stopServer() {
|
private func stopServer() {
|
||||||
print("Stopping server")
|
print("Stopping server")
|
||||||
CwMwebPlugin.server?.stop()
|
CwMwebPlugin.server?.stop()
|
||||||
CwMwebPlugin.server = nil
|
CwMwebPlugin.server = nil
|
||||||
CwMwebPlugin.port = 0
|
CwMwebPlugin.port = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
private func address(_ scanSecret: String?, _ spendPub: String?, _ index: Int?) -> String? {
|
||||||
stopServer()
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -53,6 +53,15 @@ class CwMweb {
|
||||||
await cleanup();
|
await cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<String?> 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<void> cleanup() async {
|
static Future<void> cleanup() async {
|
||||||
await _clientChannel?.terminate();
|
await _clientChannel?.terminate();
|
||||||
_rpcClient = null;
|
_rpcClient = null;
|
||||||
|
|
|
@ -19,4 +19,14 @@ class MethodChannelCwMweb extends CwMwebPlatform {
|
||||||
Future<void> stop() async {
|
Future<void> stop() async {
|
||||||
await methodChannel.invokeMethod<void>('stop');
|
await methodChannel.invokeMethod<void>('stop');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String?> address(String scanSecret, String spendPub, int index) async {
|
||||||
|
final result = await methodChannel.invokeMethod<String>('address', {
|
||||||
|
'scanSecret': scanSecret,
|
||||||
|
'spendPub': spendPub,
|
||||||
|
'index': index,
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,4 +30,8 @@ abstract class CwMwebPlatform extends PlatformInterface {
|
||||||
Future<void> stop() {
|
Future<void> stop() {
|
||||||
throw UnimplementedError('stop() has not been implemented.');
|
throw UnimplementedError('stop() has not been implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String?> address(String scanSecret, String spendPub, int index) {
|
||||||
|
throw UnimplementedError('address(int) has not been implemented.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,6 +136,7 @@ dependency_overrides:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitcoin_base
|
url: https://github.com/cake-tech/bitcoin_base
|
||||||
ref: cake-update-v6
|
ref: cake-update-v6
|
||||||
|
ffi: 2.1.0
|
||||||
|
|
||||||
flutter_icons:
|
flutter_icons:
|
||||||
image_path: "assets/images/app_logo.png"
|
image_path: "assets/images/app_logo.png"
|
||||||
|
|
Loading…
Reference in a new issue