From 7ca9c5f735da9fbffdcd51a0dacc04409b9beb3c Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Tue, 4 Jun 2024 17:08:25 +1000 Subject: [PATCH] feat: Start with signing txs --- lib/hns.dart | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/send.dart | 17 ++++++++++-- pubspec.lock | 74 +++++++++++++++++++++++++++++++++++++++++++++++++- pubspec.yaml | 6 +++++ 4 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 lib/hns.dart diff --git a/lib/hns.dart b/lib/hns.dart new file mode 100644 index 0000000..ad7da85 --- /dev/null +++ b/lib/hns.dart @@ -0,0 +1,75 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_bitcoin/flutter_bitcoin.dart' as bitcoin; +import 'dart:typed_data'; +import 'package:hex/hex.dart'; +import 'package:crypto/crypto.dart'; +import 'package:bip39/bip39.dart' as bip39; +import 'package:bip32/bip32.dart' as bip32; + +final bip32.NetworkType hnsMainnet = bip32.NetworkType( + bip32: bip32.Bip32Type(public: 0x0488b21e, private: 0x0488ade4), + wif: 0x80, +); + +final bitcoin.NetworkType hnsMainnetBitcoin = bitcoin.NetworkType( + messagePrefix: '\x18Handshake Signed Message:\n', + bech32: 'hs', + bip32: bitcoin.Bip32Type(public: 0x0488b21e, private: 0x0488ade4), + pubKeyHash: 0x00, + scriptHash: 0x05, + wif: 0x80); + +String getXpub(String seedPhrase) { + List seedints = bip39.mnemonicToSeed(seedPhrase); + Uint8List seed = Uint8List.fromList(seedints); + bip32.BIP32 master = bip32.BIP32.fromSeed(seed, hnsMainnet); + return master.derivePath("m/44'/5353'/0'").neutered().toBase58(); +} + +Future signTX(String seedPhrase, Map txData) async { + final seed = bip39.mnemonicToSeed(seedPhrase); + final master = bip32.BIP32.fromSeed(seed, hnsMainnet); + + final txb = bitcoin.TransactionBuilder( + network: hnsMainnetBitcoin, + ); + + // for (var input in txData['inputs']) { + // final prevout = input['prevout']; + // final vin = input['vin']; + // if (vin != null && vin is int) { + // final hash = prevout['hash']; + // final index = prevout['index']; + // bitcoin.ECPair keyPair = bitcoin.ECPair.fromPrivateKey( + // master.derivePath("m/44'/5353'/0'/0/$vin").privateKey!, + // network: hnsMainnetBitcoin); + // txb.addInput(hash, index); + // txb.sign(vin: vin, keyPair: keyPair); + // } else { + // print('vin is not an int'); + // print(input); + // } + // } + for (var input in txData['inputs']) { + final prevout = input['prevout']; + final coin = input['coin']; + final index = prevout['index']; + final hash = prevout['hash']; + final vin = coin['height']; + print(input); + + bitcoin.ECPair keyPair = bitcoin.ECPair.fromPrivateKey( + master.derivePath("m/44'/5353'/0'/0/$vin").privateKey!, + network: hnsMainnetBitcoin, + ); + + txb.addInput(hash, index); + txb.sign(vin: int.parse(vin.toString()), keyPair: keyPair); + } + + for (var output in txData['outputs']) { + txb.addOutput(output['address'], output['value']); + } + + return txb.build().toHex(); +} diff --git a/lib/send.dart b/lib/send.dart index 48f9263..a929b64 100644 --- a/lib/send.dart +++ b/lib/send.dart @@ -4,7 +4,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; -import 'package:qr_flutter/qr_flutter.dart'; +import 'package:flutter_bitcoin/flutter_bitcoin.dart'; +import 'package:bip39/bip39.dart' as bip39; +import 'package:bip32/bip32.dart' as bip32; +import 'package:crypto/crypto.dart'; +import 'dart:typed_data'; +import 'package:firewallet/hns.dart' as hns; class SendPage extends StatefulWidget { SendPage({Key? key, required this.uuid, required this.wallet}) @@ -168,8 +173,16 @@ class _SendPageState extends State { content: Text('Sent $amount HNS to $toAddress'), ), ); + + String seedPhrase = 'abandon abandon abandon abandon abandon abandon ' + + 'abandon abandon abandon abandon abandon about'; + print(hns.getXpub(seedPhrase)); + hns.signTX(seedPhrase, data).then((tx) { + print(tx); + }); + if (sendMax) { - amountController.text = ''; + // amountController.text = ''; } else { amountController.text = min(amount, walletBalance - 0.02).toStringAsFixed(2); diff --git a/pubspec.lock b/pubspec.lock index 69a428d..6cf55c7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,6 +25,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.11.0" + bech32: + dependency: transitive + description: + name: bech32 + sha256: "156cbace936f7720c79a79d16a03efad343b1ef17106716e04b8b8e39f99f7f7" + url: "https://pub.dev" + source: hosted + version: "0.2.2" + bip32: + dependency: "direct main" + description: + name: bip32 + sha256: "54787cd7a111e9d37394aabbf53d1fc5e2e0e0af2cd01c459147a97c0e3f8a97" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + bip39: + dependency: "direct main" + description: + name: bip39 + sha256: de1ee27ebe7d96b84bb3a04a4132a0a3007dcdd5ad27dd14aa87a29d97c45edc + url: "https://pub.dev" + source: hosted + version: "1.0.6" boolean_selector: dependency: transitive description: @@ -33,6 +57,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + bs58check: + dependency: transitive + description: + name: bs58check + sha256: c4a164d42b25c2f6bc88a8beccb9fc7d01440f3c60ba23663a20a70faf484ea9 + url: "https://pub.dev" + source: hosted + version: "1.0.2" characters: dependency: transitive description: @@ -73,8 +105,16 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" - crypto: + convert: dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + crypto: + dependency: "direct main" description: name: crypto sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab @@ -118,6 +158,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_bitcoin: + dependency: "direct main" + description: + name: flutter_bitcoin + sha256: "1a783c4d80f83b1ba5dedb4f18ebf522c90dd99e6fa0224b5228f68aa29b3442" + url: "https://pub.dev" + source: hosted + version: "1.0.1" flutter_launcher_icons: dependency: "direct dev" description: @@ -144,6 +192,14 @@ packages: description: flutter source: sdk version: "0.0.0" + hex: + dependency: "direct main" + description: + name: hex + sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a" + url: "https://pub.dev" + source: hosted + version: "0.2.0" http: dependency: "direct main" description: @@ -168,6 +224,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.2.0" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" json_annotation: dependency: transitive description: @@ -288,6 +352,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pointycastle: + dependency: "direct main" + description: + name: pointycastle + sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" + url: "https://pub.dev" + source: hosted + version: "3.9.1" qr: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 40aecbe..d25010f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,6 +39,12 @@ dependencies: http: ^1.2.1 url_launcher: ^6.2.6 qr_flutter: ^4.1.0 + flutter_bitcoin: ^1.0.1 + crypto: ^3.0.3 + pointycastle: ^3.9.1 + bip39: ^1.0.6 + bip32: ^2.0.0 + hex: ^0.2.0 dev_dependencies: flutter_test: