dev
dart 88 lines 3.32 KB
Raw
1 import 'dart:async';
2 import 'dart:typed_data';
3
4 import 'package:bitcoin_base/bitcoin_base.dart';
5 import 'package:blockchain_utils/blockchain_utils.dart';
6 import 'package:cw_bitcoin/electrum_wallet.dart';
7 import 'package:cw_bitcoin/hardware/bitcoin_hardware_wallet_service.dart';
8 import 'package:cw_bitcoin/psbt/transaction_builder.dart';
9 import 'package:cw_bitcoin/utils.dart';
10 import 'package:cw_core/hardware/hardware_account_data.dart';
11 import 'package:cw_core/hardware/hardware_wallet_service.dart';
12 import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
13 import 'package:ledger_litecoin/ledger_litecoin.dart';
14
15 class LitecoinLedgerService extends HardwareWalletService
16 with BitcoinHardwareWalletService, LitecoinHardwareWalletService {
17 LitecoinLedgerService(this.ledgerConnection)
18 : litecoinLedgerApp = LitecoinLedgerApp(ledgerConnection);
19
20 final LedgerConnection ledgerConnection;
21 final LitecoinLedgerApp litecoinLedgerApp;
22
23 @override
24 Future<List<HardwareAccountData>> getAvailableAccounts({int index = 0, int limit = 5}) async {
25 await litecoinLedgerApp.getVersion();
26
27 final accounts = <HardwareAccountData>[];
28 final indexRange = List.generate(limit, (i) => i + index);
29 final xpubVersion = Bip44Conf.litecoinMainNet.altKeyNetVer;
30
31 for (final i in indexRange) {
32 final derivationPath = "m/84'/2'/$i'";
33 final xpub = await litecoinLedgerApp.getXPubKey(
34 accountsDerivationPath: derivationPath,
35 xPubVersion: int.parse(hex.encode(xpubVersion.public), radix: 16));
36 final hd = Bip32Slip10Secp256k1.fromExtendedKey(xpub, xpubVersion).childKey(Bip32KeyIndex(0));
37
38 final address = generateP2WPKHAddress(hd: hd, index: 0, network: LitecoinNetwork.mainnet);
39
40 accounts.add(HardwareAccountData(
41 address: address,
42 accountIndex: i,
43 derivationPath: derivationPath,
44 xpub: xpub,
45 ));
46 }
47
48 return accounts;
49 }
50
51 @override
52 Future<String> signLitecoinTransaction({
53 required List<BitcoinBaseOutput> outputs,
54 required List<PSBTReadyUtxoWithAddress> inputs,
55 required Map<String, PublicKeyWithDerivationPath> publicKeys,
56 }) {
57 final readyInputs = <LedgerTransaction>[];
58 for (final utxo in inputs) {
59 final publicKeyAndDerivationPath = publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
60
61 readyInputs.add(LedgerTransaction(
62 rawTx: utxo.rawTx,
63 outputIndex: utxo.utxo.vout,
64 ownerPublicKey: Uint8List.fromList(hex.decode(publicKeyAndDerivationPath.publicKey)),
65 ownerDerivationPath: publicKeyAndDerivationPath.derivationPath,
66 ));
67 }
68
69 // Check if we have the key to one of the output addresses to hide change on the device
70 String? changePath;
71 for (final output in outputs) {
72 final maybeChangePath = publicKeys[(output as BitcoinOutput).address.pubKeyHash()];
73 if (maybeChangePath != null) changePath ??= maybeChangePath.derivationPath;
74 }
75
76 return litecoinLedgerApp.createTransaction(
77 inputs: readyInputs,
78 outputs: outputs
79 .map((e) => TransactionOutput.fromBigInt((e as BitcoinOutput).value,
80 Uint8List.fromList(e.address.toScriptPubKey().toBytes())))
81 .toList(),
82 changePath: changePath,
83 sigHashType: 0x01,
84 additionals: ["bech32"],
85 isSegWit: true,
86 useTrustedInputForSegwit: true);
87 }
88 }