Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CW 693 Add Ledger bitcoin cash support #1615

Draft
wants to merge 30 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8efd4a0
Add Litecoin Hardware Wallet Creation
konstantinullrich Jul 15, 2024
a24a733
Add Litecoin Hardware Wallet Creation
konstantinullrich Jul 17, 2024
fbab1ee
Fix Bitcoin not sending on Ledger
konstantinullrich Jul 17, 2024
615751f
Merge branch 'main' into fixing-ledger-problems
konstantinullrich Jul 19, 2024
e7d07c7
Merge branch 'refs/heads/fixing-ledger-problems' into CW-679-Add-Ledg…
konstantinullrich Jul 19, 2024
4f47d27
Fixes to sending LTC using Ledger
konstantinullrich Jul 30, 2024
0749178
Merge branch 'main' into CW-679-Add-Ledger-Litecoin-Support
konstantinullrich Jul 30, 2024
0473d28
Merge branch 'refs/heads/main' into CW-679-Add-Ledger-Litecoin-Support
konstantinullrich Aug 9, 2024
7b41c0b
Merge branch 'refs/heads/main' into CW-679-Add-Ledger-Litecoin-Support
konstantinullrich Aug 12, 2024
bad2be9
CW-679 Fix merge conflicts
konstantinullrich Aug 12, 2024
17ec9b9
CW-679 Fix merge conflicts
konstantinullrich Aug 12, 2024
8f70373
Merge branch 'refs/heads/main' into CW-679-Add-Ledger-Litecoin-Support
konstantinullrich Aug 15, 2024
1c3db7f
CW-679 Minor fixes
konstantinullrich Aug 15, 2024
71abf6a
CW-679 Add derivation Path of change address
konstantinullrich Aug 15, 2024
b94d634
Merge branch 'refs/heads/main' into CW-679-Add-Ledger-Litecoin-Support
konstantinullrich Aug 16, 2024
3dc0bcf
CW-679 Add BitcoinCash Support
konstantinullrich Aug 16, 2024
557745e
CW-679 Add BitcoinCash Support
konstantinullrich Aug 16, 2024
1c2de6c
CW-679 Add BitcoinCash Default DerivationInfo
konstantinullrich Aug 16, 2024
ab165e5
Merge branch 'refs/heads/main' into CW-679-Add-Ledger-Litecoin-Support
konstantinullrich Sep 3, 2024
1bf3f24
ledger flutter plus refactoring
konstantinullrich Sep 16, 2024
a30c0be
Merge remote-tracking branch 'origin/CW-679-Add-Ledger-Litecoin-Suppo…
konstantinullrich Sep 16, 2024
0f09991
ledger flutter plus refactoring
konstantinullrich Sep 16, 2024
14a7100
ledger flutter plus refactoring
konstantinullrich Sep 16, 2024
0171808
Merge remote-tracking branch 'origin/main' into CW-679-Add-Ledger-Lit…
konstantinullrich Sep 16, 2024
42f4eda
Ups :|
konstantinullrich Sep 16, 2024
6b8237b
Ups :| I forgot USB
konstantinullrich Sep 16, 2024
474ead2
Merge branch 'CW-679-Add-Ledger-Litecoin-Support' into CW-693-Add-Led…
konstantinullrich Sep 17, 2024
1e91aa8
Upgrading to Ledger Flutter Plus
konstantinullrich Sep 17, 2024
e9d5da0
Upgrading to Ledger Flutter Plus
konstantinullrich Sep 17, 2024
25a2cb1
Upgrading to Ledger Flutter Plus
konstantinullrich Sep 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions cw_bitcoin/lib/bitcoin_hardware_wallet_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,31 @@ import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/utils.dart';
import 'package:cw_core/hardware/hardware_account_data.dart';
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
import 'package:ledger_flutter/ledger_flutter.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';

class BitcoinHardwareWalletService {
BitcoinHardwareWalletService(this.ledger, this.device);
BitcoinHardwareWalletService(this.ledgerConnection);

final Ledger ledger;
final LedgerDevice device;
final LedgerConnection ledgerConnection;

Future<List<HardwareAccountData>> getAvailableAccounts({int index = 0, int limit = 5}) async {
final bitcoinLedgerApp = BitcoinLedgerApp(ledger);
Future<List<HardwareAccountData>> getAvailableAccounts(
{int index = 0, int limit = 5}) async {
final bitcoinLedgerApp = BitcoinLedgerApp(ledgerConnection);

final masterFp = await bitcoinLedgerApp.getMasterFingerprint(device);
print(masterFp);
final masterFp = await bitcoinLedgerApp.getMasterFingerprint();

final accounts = <HardwareAccountData>[];
final indexRange = List.generate(limit, (i) => i + index);

for (final i in indexRange) {
final derivationPath = "m/84'/0'/$i'";
final xpub = await bitcoinLedgerApp.getXPubKey(device, derivationPath: derivationPath);
final xpub =
await bitcoinLedgerApp.getXPubKey(derivationPath: derivationPath);
Bip32Slip10Secp256k1 hd =
Bip32Slip10Secp256k1.fromExtendedKey(xpub).childKey(Bip32KeyIndex(0));

final address = generateP2WPKHAddress(hd: hd, index: 0, network: BitcoinNetwork.mainnet);
final address = generateP2WPKHAddress(
hd: hd, index: 0, network: BitcoinNetwork.mainnet);

accounts.add(HardwareAccountData(
address: address,
Expand Down
56 changes: 32 additions & 24 deletions cw_bitcoin/lib/bitcoin_wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ 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/bitcoin_mnemonic.dart';
import 'package:cw_bitcoin/psbt_transaction_builder.dart';
import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
import 'package:cw_bitcoin/electrum_balance.dart';
import 'package:cw_bitcoin/electrum_wallet.dart';
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
import 'package:cw_bitcoin/psbt_transaction_builder.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_keys_file.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
import 'package:ledger_flutter/ledger_flutter.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
import 'package:mobx/mobx.dart';

part 'bitcoin_wallet.g.dart';
Expand Down Expand Up @@ -61,8 +61,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
initialBalance: initialBalance,
seedBytes: seedBytes,
encryptionFileUtils: encryptionFileUtils,
currency:
networkParam == BitcoinNetwork.testnet ? CryptoCurrency.tbtc : CryptoCurrency.btc,
currency: networkParam == BitcoinNetwork.testnet
? CryptoCurrency.tbtc
: CryptoCurrency.btc,
alwaysScan: alwaysScan,
) {
// in a standard BIP44 wallet, mainHd derivation path = m/84'/0'/0'/0 (account 0, index unspecified here)
Expand All @@ -80,11 +81,13 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
mainHd: hd,
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
network: networkParam ?? network,
masterHd: seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
masterHd:
seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
);

autorun((_) {
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
this.walletAddresses.isEnabledAutoGenerateSubaddress =
this.isEnabledAutoGenerateSubaddress;
});
}

Expand Down Expand Up @@ -185,8 +188,10 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
walletInfo.derivationInfo ??= DerivationInfo();

// set the default if not present:
walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? electrum_path;
walletInfo.derivationInfo!.derivationType ??= snp?.derivationType ?? DerivationType.electrum;
walletInfo.derivationInfo!.derivationPath ??=
snp?.derivationPath ?? electrum_path;
walletInfo.derivationInfo!.derivationType ??=
snp?.derivationType ?? DerivationType.electrum;

Uint8List? seedBytes = null;
final mnemonic = keysData.mnemonic;
Expand Down Expand Up @@ -228,15 +233,14 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
);
}

Ledger? _ledger;
LedgerDevice? _ledgerDevice;
LedgerConnection? _ledgerConnection;
BitcoinLedgerApp? _bitcoinLedgerApp;

void setLedger(Ledger setLedger, LedgerDevice setLedgerDevice) {
_ledger = setLedger;
_ledgerDevice = setLedgerDevice;
_bitcoinLedgerApp =
BitcoinLedgerApp(_ledger!, derivationPath: walletInfo.derivationInfo!.derivationPath!);
@override
void setLedgerConnection(LedgerConnection connection) {
_ledgerConnection = connection;
_bitcoinLedgerApp = BitcoinLedgerApp(_ledgerConnection!,
derivationPath: walletInfo.derivationInfo!.derivationPath!);
}

@override
Expand All @@ -251,12 +255,14 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
BitcoinOrdering inputOrdering = BitcoinOrdering.bip69,
BitcoinOrdering outputOrdering = BitcoinOrdering.bip69,
}) async {
final masterFingerprint = await _bitcoinLedgerApp!.getMasterFingerprint(_ledgerDevice!);
final masterFingerprint = await _bitcoinLedgerApp!.getMasterFingerprint();

final psbtReadyInputs = <PSBTReadyUtxoWithAddress>[];
for (final utxo in utxos) {
final rawTx = await electrumClient.getTransactionHex(hash: utxo.utxo.txHash);
final publicKeyAndDerivationPath = publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
final rawTx =
await electrumClient.getTransactionHex(hash: utxo.utxo.txHash);
final publicKeyAndDerivationPath =
publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;

psbtReadyInputs.add(PSBTReadyUtxoWithAddress(
utxo: utxo.utxo,
Expand All @@ -268,25 +274,27 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
));
}

final psbt =
PSBTTransactionBuild(inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);
final psbt = PSBTTransactionBuild(
inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);

final rawHex = await _bitcoinLedgerApp!.signPsbt(_ledgerDevice!, psbt: psbt.psbt);
final rawHex = await _bitcoinLedgerApp!.signPsbt(psbt: psbt.psbt);
return BtcTransaction.fromRaw(BytesUtils.toHexString(rawHex));
}

@override
Future<String> signMessage(String message, {String? address = null}) async {
if (walletInfo.isHardwareWallet) {
final addressEntry = address != null
? walletAddresses.allAddresses.firstWhere((element) => element.address == address)
? walletAddresses.allAddresses
.firstWhere((element) => element.address == address)
: null;
final index = addressEntry?.index ?? 0;
final isChange = addressEntry?.isHidden == true ? 1 : 0;
final accountPath = walletInfo.derivationInfo?.derivationPath;
final derivationPath = accountPath != null ? "$accountPath/$isChange/$index" : null;
final derivationPath =
accountPath != null ? "$accountPath/$isChange/$index" : null;

final signature = await _bitcoinLedgerApp!.signMessage(_ledgerDevice!,
final signature = await _bitcoinLedgerApp!.signMessage(
message: ascii.encode(message), signDerivationPath: derivationPath);
return base64Encode(signature);
}
Expand Down
2 changes: 1 addition & 1 deletion cw_bitcoin/lib/electrum.dart
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ class ElectrumClient {
try {
final result = await callWithTimeout(
method: 'blockchain.transaction.get', params: [hash, verbose], timeout: 10000);
if (result is Map<String, dynamic>) {
if (result is Map<String, dynamic> || result is String) {
return result;
}
} on RequestFailedTimeoutException catch (_) {
Expand Down
Loading
Loading