mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
Cw 604 integrate bitcoin ledger (#1407)
* CW-503 Prepare Ledger integration * CW-503 Revert Tor ignore * CW-503 Add Connect Device Page * CW-503 Add createWalletFromDevice for monero * CW-503 Add Connect Device Page * CW-503 Add Connect Device Page * CW-503 Add Debug Options * CW-503 Add proper hardware wallet selection screen * CW-503 Minor design changes on connect_device_page * CW-503 Add Create Wallet from Ledger * CW-503 Spent Ledger ETH Funds * CW-503 Minor fixes * CW-503 Fix Merge conflicts * CW-503 Fix Merge conflicts * CW-503 Fix Merge conflicts * CW-503 Fix minor conflicts * CW-503 Improve Ledger BLE Communication * CW-503 Improve Ledger BLE Communication * CW-503 Rollback Monero Test code * CW-503 Fix Execution failed for task :app:checkReleaseDuplicateClasses * CW-503 Better Error-Exceptions * CW-503 Add SetPinScreen before restore from hardware-wallet * CW-503 override web3dart to use cake's git hosted version * CW-503 Implement ledger sign messages * CW-503 Implement ledger sign messages and send erc20 tokens * CW-503 Fix merge conflicts * CW-503 Fix merge conflicts * CW-503 Use dep override for ledger_flutter * CW-503 Ledger ERC20 finalisation * CW-503 More graceful error handling * CW-503 Even more graceful error handling & remove debug code * CW-503 Minor Changes for Vik * CW-503 Fix USB connection * CW-503 Maybe this overrides web3dart finally * Indicate Loading on the first 5 Wallet Accounts * Prepare Ledger Bitcoin * Fix conflicts with main * Add Bluetooth permission to iOS [skip ci] * add privacyinfo for ios [skip ci] * update PrivacyInfo.xcprivacy [scip ci] * ios shit [skip ci] * Improve bitcoin xpub * Resolve open Todos regarding iOS Support * Minor debug * Remove erc20 dependency to have more granular control over the tx UX * Create Bitcoin Wallets using xpub * Create Bitcoin Wallets using xpub * Better error handling * Improve Ledger account handling * Add Bitcoin Support for Ledger * Add Bitcoin Support for Ledger * Add Bitcoin Support for Ledger * Implement requested Changes * Implement requested Changes * Minor fix * Implement requested Changes * Implement requested Changes * Add comment to remind me * Enable RBF for Bitcoin Ledger * Fix merge conflicts * Update wallet_info.dart * Cw 503 ledger support (#1310) * CW-503 Prepare Ledger integration * CW-503 Revert Tor ignore * CW-503 Add Connect Device Page * CW-503 Add createWalletFromDevice for monero * CW-503 Add Connect Device Page * CW-503 Add Connect Device Page * CW-503 Add Debug Options * CW-503 Add proper hardware wallet selection screen * CW-503 Minor design changes on connect_device_page * CW-503 Add Create Wallet from Ledger * CW-503 Spent Ledger ETH Funds * CW-503 Minor fixes * CW-503 Fix Merge conflicts * CW-503 Fix Merge conflicts * CW-503 Fix Merge conflicts * CW-503 Fix minor conflicts * CW-503 Improve Ledger BLE Communication * CW-503 Improve Ledger BLE Communication * CW-503 Rollback Monero Test code * CW-503 Fix Execution failed for task :app:checkReleaseDuplicateClasses * CW-503 Better Error-Exceptions * CW-503 Add SetPinScreen before restore from hardware-wallet * CW-503 override web3dart to use cake's git hosted version * CW-503 Implement ledger sign messages * CW-503 Implement ledger sign messages and send erc20 tokens * CW-503 Fix merge conflicts * CW-503 Fix merge conflicts * CW-503 Use dep override for ledger_flutter * CW-503 Ledger ERC20 finalisation * CW-503 More graceful error handling * CW-503 Even more graceful error handling & remove debug code * CW-503 Minor Changes for Vik * CW-503 Fix USB connection * CW-503 Maybe this overrides web3dart finally * Indicate Loading on the first 5 Wallet Accounts * Fix conflicts with main * Add Bluetooth permission to iOS [skip ci] * add privacyinfo for ios [skip ci] * update PrivacyInfo.xcprivacy [scip ci] * ios shit [skip ci] * Resolve open Todos regarding iOS Support * Remove erc20 dependency to have more granular control over the tx UX * Better error handling * Improve Ledger account handling * Implement requested Changes * Implement requested Changes * Implement requested Changes * Implement requested Changes * Fix merge conflicts * Update wallet_info.dart --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> * Fix merge conflicts * Fix merge conflicts * Minor Fix to derivations * Update cw_bitcoin/lib/bitcoin_wallet.dart [skip ci] * Update cw_bitcoin/lib/bitcoin_wallet.dart [skip ci] * Update cw_bitcoin/lib/electrum_wallet.dart [skip ci] * Fix backward compatibility issues * Merge Tron * Fix Tron with HW changes * fix ble on iOS fix tron address validation --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
co-authored by
Omar Hatem
parent
043d7d7c8b
commit
5eabdcdca1
@@ -509,7 +509,9 @@ abstract class DashboardViewModelBase with Store {
|
||||
final path = await pathForWallet(name: walletInfo.name, type: walletInfo.type);
|
||||
final jsonSource = await read(path: path, password: password);
|
||||
final data = json.decode(jsonSource) as Map;
|
||||
final mnemonic = data['mnemonic'] as String;
|
||||
final mnemonic = data['mnemonic'] as String?;
|
||||
|
||||
if (mnemonic == null) continue;
|
||||
|
||||
final hash = await Cryptography.instance.sha256().hash(utf8.encode(mnemonic));
|
||||
final seedSha = bytesToHex(hash.bytes);
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/polygon/polygon.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
class LedgerViewModel {
|
||||
final Ledger ledger = Ledger(
|
||||
options: LedgerOptions(
|
||||
scanMode: ScanMode.balanced,
|
||||
maxScanDuration: const Duration(minutes: 5),
|
||||
),
|
||||
onPermissionRequest: (_) async {
|
||||
Map<Permission, PermissionStatus> statuses = await [
|
||||
Permission.bluetoothScan,
|
||||
Permission.bluetoothConnect,
|
||||
Permission.bluetoothAdvertise,
|
||||
].request();
|
||||
|
||||
return statuses.values.where((status) => status.isDenied).isEmpty;
|
||||
},
|
||||
);
|
||||
|
||||
Future<void> connectLedger(LedgerDevice device) async {
|
||||
await ledger.connect(device);
|
||||
|
||||
if (device.connectionType == ConnectionType.usb) _device = device;
|
||||
}
|
||||
|
||||
LedgerDevice? _device;
|
||||
|
||||
bool get isConnected => ledger.devices.isNotEmpty || _device != null;
|
||||
|
||||
LedgerDevice get device => _device ?? ledger.devices.first;
|
||||
|
||||
void setLedger(WalletBase wallet) {
|
||||
switch (wallet.type) {
|
||||
case WalletType.bitcoin:
|
||||
return bitcoin!.setLedger(wallet, ledger, device);
|
||||
case WalletType.ethereum:
|
||||
return ethereum!.setLedger(wallet, ledger, device);
|
||||
case WalletType.polygon:
|
||||
return polygon!.setLedger(wallet, ledger, device);
|
||||
default:
|
||||
throw Exception('Unexpected wallet type: ${wallet.type}');
|
||||
}
|
||||
}
|
||||
|
||||
String? interpretErrorCode(String errorCode) {
|
||||
switch (errorCode) {
|
||||
case "6985":
|
||||
return S.current.ledger_error_tx_rejected_by_user;
|
||||
case "5515":
|
||||
return S.current.ledger_error_device_locked;
|
||||
case "6d02": // UNKNOWN_APDU
|
||||
case "6511":
|
||||
case "6e00":
|
||||
return S.current.ledger_error_wrong_app;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,13 @@ import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
||||
import 'package:cw_core/exceptions.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cake_wallet/view_model/send/output.dart';
|
||||
import 'package:cake_wallet/view_model/send/send_template_view_model.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/entities/template.dart';
|
||||
import 'package:cake_wallet/core/address_validator.dart';
|
||||
@@ -63,6 +65,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
this.balanceViewModel,
|
||||
this.contactListViewModel,
|
||||
this.transactionDescriptionBox,
|
||||
this.ledgerViewModel,
|
||||
) : state = InitialExecutionState(),
|
||||
currencies = appStore.wallet!.balance.keys.toList(),
|
||||
selectedCryptoCurrency = appStore.wallet!.currency,
|
||||
@@ -266,6 +269,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
final SendTemplateViewModel sendTemplateViewModel;
|
||||
final BalanceViewModel balanceViewModel;
|
||||
final ContactListViewModel contactListViewModel;
|
||||
final LedgerViewModel ledgerViewModel;
|
||||
final FiatConversionStore _fiatConversationStore;
|
||||
final Box<TransactionDescription> transactionDescriptionBox;
|
||||
|
||||
@@ -340,7 +344,10 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
try {
|
||||
state = IsExecutingState();
|
||||
|
||||
if (wallet.isHardwareWallet) state = IsAwaitingDeviceResponseState();
|
||||
|
||||
pendingTransaction = await wallet.createTransaction(_credentials());
|
||||
|
||||
if (provider is ThorChainExchangeProvider) {
|
||||
final outputCount = pendingTransaction?.outputCount ?? 0;
|
||||
if (outputCount > 10) {
|
||||
@@ -354,7 +361,15 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
state = ExecutedSuccessfullyState();
|
||||
return pendingTransaction;
|
||||
} catch (e) {
|
||||
state = FailureState(translateErrorMessage(e, wallet.type, wallet.currency));
|
||||
if (e is LedgerException) {
|
||||
final errorCode = e.errorCode.toRadixString(16);
|
||||
final fallbackMsg = e.message.isNotEmpty ? e.message : "Unexpected Ledger Error Code: $errorCode";
|
||||
final errorMsg = ledgerViewModel.interpretErrorCode(errorCode) ?? fallbackMsg;
|
||||
|
||||
state = FailureState(errorMsg);
|
||||
} else {
|
||||
state = FailureState(translateErrorMessage(e, wallet.type, wallet.currency));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -390,15 +405,13 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
|
||||
String address = outputs.fold('', (acc, value) {
|
||||
return value.isParsedAddress
|
||||
? acc + value.address + '\n' + value.extractedAddress + '\n\n'
|
||||
: acc + value.address + '\n\n';
|
||||
? '$acc${value.address}\n${value.extractedAddress}\n\n'
|
||||
: '$acc${value.address}\n\n';
|
||||
});
|
||||
|
||||
address = address.trim();
|
||||
|
||||
String note = outputs.fold('', (acc, value) {
|
||||
return acc + value.note + '\n';
|
||||
});
|
||||
String note = outputs.fold('', (acc, value) => '$acc${value.note}\n');
|
||||
|
||||
note = note.trim();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
|
||||
class IsAwaitingDeviceResponseState extends IsExecutingState {}
|
||||
class TransactionCommitting extends ExecutionState {}
|
||||
class TransactionCommitted extends ExecutionState {}
|
||||
|
||||
@@ -72,6 +72,7 @@ abstract class WalletCreationVMBase with Store {
|
||||
address: '',
|
||||
showIntroCakePayCard: (!walletCreationService.typeExists(type)) && type != WalletType.haven,
|
||||
derivationInfo: credentials.derivationInfo ?? getDefaultDerivation(),
|
||||
hardwareWalletType: credentials.hardwareWalletType,
|
||||
);
|
||||
|
||||
credentials.walletInfo = walletInfo;
|
||||
@@ -99,7 +100,7 @@ abstract class WalletCreationVMBase with Store {
|
||||
case WalletType.litecoin:
|
||||
return DerivationInfo(
|
||||
derivationType: DerivationType.electrum,
|
||||
derivationPath: "m/0'/0",
|
||||
derivationPath: "m/0'",
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/polygon/polygon.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||
import 'package:cw_core/hardware/hardware_account_data.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'wallet_hardware_restore_view_model.g.dart';
|
||||
|
||||
class WalletHardwareRestoreViewModel = WalletHardwareRestoreViewModelBase
|
||||
with _$WalletHardwareRestoreViewModel;
|
||||
|
||||
abstract class WalletHardwareRestoreViewModelBase extends WalletCreationVM with Store {
|
||||
final LedgerViewModel ledgerViewModel;
|
||||
|
||||
int _nextIndex = 0;
|
||||
|
||||
WalletHardwareRestoreViewModelBase(this.ledgerViewModel, AppStore appStore,
|
||||
WalletCreationService walletCreationService, Box<WalletInfo> walletInfoSource,
|
||||
{required WalletType type})
|
||||
: super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true);
|
||||
|
||||
@observable
|
||||
String name = "";
|
||||
|
||||
@observable
|
||||
HardwareAccountData? selectedAccount = null;
|
||||
|
||||
@observable
|
||||
bool isLoadingMoreAccounts = false;
|
||||
|
||||
@observable
|
||||
String? error = null;
|
||||
|
||||
// @observable
|
||||
ObservableList<HardwareAccountData> availableAccounts = ObservableList();
|
||||
|
||||
@action
|
||||
Future<void> getNextAvailableAccounts(int limit) async {
|
||||
try {
|
||||
List<HardwareAccountData> accounts;
|
||||
switch (type) {
|
||||
case WalletType.bitcoin:
|
||||
accounts = await bitcoin!
|
||||
.getHardwareWalletAccounts(ledgerViewModel, index: _nextIndex, limit: limit);
|
||||
break;
|
||||
case WalletType.ethereum:
|
||||
accounts = await ethereum!
|
||||
.getHardwareWalletAccounts(ledgerViewModel, index: _nextIndex, limit: limit);
|
||||
break;
|
||||
case WalletType.polygon:
|
||||
accounts = await polygon!
|
||||
.getHardwareWalletAccounts(ledgerViewModel, index: _nextIndex, limit: limit);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
availableAccounts.addAll(accounts);
|
||||
_nextIndex += limit;
|
||||
} on LedgerException catch (e) {
|
||||
error = ledgerViewModel.interpretErrorCode(e.errorCode.toRadixString(16));
|
||||
} catch (e) {
|
||||
error = S.current.ledger_connection_error;
|
||||
}
|
||||
|
||||
isLoadingMoreAccounts = false;
|
||||
_nextIndex += limit;
|
||||
}
|
||||
|
||||
@override
|
||||
WalletCredentials getCredentials(dynamic _options) {
|
||||
WalletCredentials credentials;
|
||||
switch (type) {
|
||||
case WalletType.bitcoin:
|
||||
credentials =
|
||||
bitcoin!.createBitcoinHardwareWalletCredentials(name: name, accountData: selectedAccount!);
|
||||
break;
|
||||
case WalletType.ethereum:
|
||||
credentials =
|
||||
ethereum!.createEthereumHardwareWalletCredentials(name: name, hwAccountData: selectedAccount!);
|
||||
break;
|
||||
case WalletType.polygon:
|
||||
credentials = polygon!.createPolygonHardwareWalletCredentials(name: name, hwAccountData: selectedAccount!);
|
||||
break;
|
||||
default:
|
||||
throw Exception('Unexpected type: ${type.toString()}');
|
||||
}
|
||||
|
||||
credentials.hardwareWalletType = HardwareWalletType.ledger;
|
||||
|
||||
return credentials;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<WalletBase> process(WalletCredentials credentials) async {
|
||||
walletCreationService.changeWalletType(type: type);
|
||||
return walletCreationService.restoreFromHardwareWallet(credentials);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user