mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-20 06:08:34 +02:00
LCW-1128-Add-support-for-Trezor (#2565)
* feat: add support for Trezor hardware wallet integration Restore Wallets * feat: add Trezor hardware wallet support, implement RLP decoding utility, and update transaction signing logic * feat: add bitcoin trezor signing * chore: update Trezor Connect dependency to specific commit hash in pubspec_base.yaml * feat: add trezor support for litecoin * feat: add colorFilter for device manufacturer icons to align with theme styles * refactor: optimize Trezor callback handling * feat: add BitBox and Trezor support for Bitcoin and Litecoin, update transaction signing logic, and improve modularity in hardware wallet services * refactor: simplify constructor assertions in `BaseBottomSheetWidget` and cleanup Trezor chainId handling logic * feat: conditionally render device manufacturers based on platform and hide SeedSigner for now
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
@@ -29,28 +31,62 @@ class SelectDeviceManufacturerPage extends BasePage {
|
||||
@override
|
||||
AppBarStyle get appBarStyle => AppBarStyle.regular;
|
||||
|
||||
ColorFilter get _colorFilter =>
|
||||
ColorFilter.mode(currentTheme.colorScheme.onSurface, BlendMode.srcIn);
|
||||
|
||||
List<_DeviceManufacturer> get availableManufacturers => [
|
||||
_DeviceManufacturer(
|
||||
image: SvgPicture.asset('assets/images/hardware_wallet/ledger_man.svg', height: 25),
|
||||
image: SvgPicture.asset(
|
||||
'assets/images/hardware_wallet/ledger_man.svg',
|
||||
height: 25,
|
||||
colorFilter: _colorFilter,
|
||||
),
|
||||
hardwareWalletType: HardwareWalletType.ledger,
|
||||
),
|
||||
// _DeviceManufacturer(
|
||||
// image: SvgPicture.asset('assets/images/hardware_wallet/bitbox_man.svg', height: 25),
|
||||
// hardwareWalletType: HardwareWalletType.bitbox,
|
||||
// tag: S.current.new_tag,
|
||||
// ),
|
||||
if (Platform.isAndroid) ...[
|
||||
_DeviceManufacturer(
|
||||
image: SvgPicture.asset(
|
||||
'assets/images/hardware_wallet/trezor_man.svg',
|
||||
height: 25,
|
||||
colorFilter: _colorFilter,
|
||||
),
|
||||
hardwareWalletType: HardwareWalletType.trezor,
|
||||
tag: S.current.new_tag,
|
||||
),
|
||||
_DeviceManufacturer(
|
||||
image: SvgPicture.asset(
|
||||
'assets/images/hardware_wallet/bitbox_man.svg',
|
||||
height: 25,
|
||||
colorFilter: _colorFilter,
|
||||
),
|
||||
hardwareWalletType: HardwareWalletType.bitbox,
|
||||
tag: S.current.new_tag,
|
||||
),
|
||||
],
|
||||
_DeviceManufacturer(
|
||||
image: SvgPicture.asset('assets/images/hardware_wallet/cupcake_man.svg', height: 25),
|
||||
image: SvgPicture.asset(
|
||||
'assets/images/hardware_wallet/cupcake_man.svg',
|
||||
height: 25,
|
||||
colorFilter: _colorFilter,
|
||||
),
|
||||
hardwareWalletType: HardwareWalletType.cupcake,
|
||||
tag: S.current.new_tag,
|
||||
),
|
||||
_DeviceManufacturer(
|
||||
image: SvgPicture.asset('assets/images/hardware_wallet/coldcard_man.svg', height: 25),
|
||||
image: SvgPicture.asset(
|
||||
'assets/images/hardware_wallet/coldcard_man.svg',
|
||||
height: 25,
|
||||
colorFilter: _colorFilter,
|
||||
),
|
||||
hardwareWalletType: HardwareWalletType.coldcard,
|
||||
tag: S.current.new_tag,
|
||||
),
|
||||
// _DeviceManufacturer(
|
||||
// image: SvgPicture.asset('assets/images/hardware_wallet/seedsigner_man.svg', height: 25),
|
||||
// image: SvgPicture.asset(
|
||||
// 'assets/images/hardware_wallet/seedsigner_man.svg',
|
||||
// height: 25,
|
||||
// colorFilter: _colorFilter,
|
||||
// ),
|
||||
// hardwareWalletType: HardwareWalletType.seedsigner,
|
||||
// tag: S.current.new_tag,
|
||||
// ),
|
||||
@@ -61,26 +97,40 @@ class SelectDeviceManufacturerPage extends BasePage {
|
||||
.toList();
|
||||
|
||||
List<_DeviceManufacturer> get comingManufacturers => [
|
||||
if (!Platform.isAndroid) ...[
|
||||
_DeviceManufacturer(
|
||||
image: SvgPicture.asset(
|
||||
'assets/images/hardware_wallet/bitbox_man.svg',
|
||||
height: 25,
|
||||
colorFilter: _colorFilter,
|
||||
),
|
||||
hardwareWalletType: HardwareWalletType.bitbox,
|
||||
tag: S.current.coming_soon_tag,
|
||||
),
|
||||
],
|
||||
_DeviceManufacturer(
|
||||
image: SvgPicture.asset('assets/images/hardware_wallet/trezor_man.svg', height: 25),
|
||||
tag: S.current.coming_soon_tag,
|
||||
),
|
||||
_DeviceManufacturer(
|
||||
image: SvgPicture.asset('assets/images/hardware_wallet/bitbox_man.svg', height: 25),
|
||||
hardwareWalletType: HardwareWalletType.bitbox,
|
||||
tag: S.current.coming_soon_tag,
|
||||
),
|
||||
_DeviceManufacturer(
|
||||
image: SvgPicture.asset('assets/images/hardware_wallet/seedsigner_man.svg', height: 25),
|
||||
image: SvgPicture.asset(
|
||||
'assets/images/hardware_wallet/seedsigner_man.svg',
|
||||
height: 25,
|
||||
colorFilter: _colorFilter,
|
||||
),
|
||||
hardwareWalletType: HardwareWalletType.seedsigner,
|
||||
tag: S.current.coming_soon_tag,
|
||||
),
|
||||
_DeviceManufacturer(
|
||||
image: SvgPicture.asset('assets/images/hardware_wallet/foundation_man.svg', height: 25),
|
||||
image: SvgPicture.asset(
|
||||
'assets/images/hardware_wallet/foundation_man.svg',
|
||||
height: 25,
|
||||
colorFilter: _colorFilter,
|
||||
),
|
||||
tag: S.current.coming_soon_tag,
|
||||
),
|
||||
_DeviceManufacturer(
|
||||
image: SvgPicture.asset('assets/images/hardware_wallet/keystone_man.svg', height: 25),
|
||||
image: SvgPicture.asset(
|
||||
'assets/images/hardware_wallet/keystone_man.svg',
|
||||
height: 25,
|
||||
colorFilter: _colorFilter,
|
||||
),
|
||||
tag: S.current.coming_soon_tag,
|
||||
),
|
||||
];
|
||||
@@ -90,48 +140,52 @@ class SelectDeviceManufacturerPage extends BasePage {
|
||||
child: Center(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Column(
|
||||
children: [
|
||||
...availableManufacturers.map(
|
||||
(manufacturer) => Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: ManufacturerOptionTile(
|
||||
image: manufacturer.image,
|
||||
tag: manufacturer.tag,
|
||||
onPressed: () {
|
||||
if (onSelect != null)
|
||||
return onSelect!.call(context, manufacturer.hardwareWalletType!);
|
||||
|
||||
if (isAirgappedWallet(manufacturer.hardwareWalletType)) {
|
||||
_onScanQRCode(context, manufacturer.hardwareWalletType!);
|
||||
} else if (manufacturer.hardwareWalletType != null) {
|
||||
Navigator.pushNamed(context, Routes.connectHardwareWallet,
|
||||
arguments: [manufacturer.hardwareWalletType]);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
if (showUnavailable) ...[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20, bottom: 10),
|
||||
child: DottedDivider(color: Theme.of(context).colorScheme.surfaceContainer),
|
||||
),
|
||||
...comingManufacturers.map(
|
||||
height: double.infinity,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
...availableManufacturers.map(
|
||||
(manufacturer) => Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: ManufacturerOptionTile(
|
||||
image: manufacturer.image,
|
||||
tag: manufacturer.tag,
|
||||
onPressed: () =>
|
||||
Fluttertoast.showToast(msg: 'One more tap and it might work'),
|
||||
// Ester egg
|
||||
isUnavailable: true,
|
||||
onPressed: () {
|
||||
if (onSelect != null)
|
||||
return onSelect!.call(context, manufacturer.hardwareWalletType!);
|
||||
|
||||
if (isAirgappedWallet(manufacturer.hardwareWalletType)) {
|
||||
_onScanQRCode(context, manufacturer.hardwareWalletType!);
|
||||
} else if (manufacturer.hardwareWalletType != null) {
|
||||
Navigator.pushNamed(context, Routes.connectHardwareWallet,
|
||||
arguments: [manufacturer.hardwareWalletType]);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
],
|
||||
if (showUnavailable) ...[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20, bottom: 10),
|
||||
child: DottedDivider(color: Theme.of(context).colorScheme.surfaceContainer),
|
||||
),
|
||||
...comingManufacturers.map(
|
||||
(manufacturer) => Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: ManufacturerOptionTile(
|
||||
image: manufacturer.image,
|
||||
tag: manufacturer.tag,
|
||||
onPressed: () =>
|
||||
Fluttertoast.showToast(msg: 'One more tap and it might work'),
|
||||
// Ester egg
|
||||
|
||||
isUnavailable: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -33,10 +33,12 @@ class CryptoBalanceWidget extends StatelessWidget {
|
||||
switch (dashboardViewModel.wallet.hardwareWalletType) {
|
||||
case null:
|
||||
return null;
|
||||
case HardwareWalletType.ledger:
|
||||
return "assets/images/hardware_wallet/device_ledger_nano_x.svg";
|
||||
case HardwareWalletType.bitbox:
|
||||
return "assets/images/hardware_wallet/device_bitbox.svg";
|
||||
case HardwareWalletType.ledger:
|
||||
return "assets/images/hardware_wallet/device_ledger_nano_x.svg";
|
||||
case HardwareWalletType.trezor:
|
||||
return "assets/images/hardware_wallet/device_trezor_safe_5.svg";
|
||||
case HardwareWalletType.cupcake:
|
||||
return "assets/images/cupcake.svg";
|
||||
case HardwareWalletType.coldcard:
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/core/node_switching_service.dart';
|
||||
import 'package:cake_wallet/core/totp_request_details.dart';
|
||||
import 'package:cake_wallet/core/trade_monitor.dart';
|
||||
import 'package:cake_wallet/entities/qr_scanner.dart';
|
||||
import 'package:cake_wallet/reactions/wallet_utils.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/authentication_store.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/utils/socket_health_logger.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/authentication_store.dart';
|
||||
import 'package:cake_wallet/entities/qr_scanner.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:trezor_connect/trezor_connect.dart';
|
||||
import 'package:uni_links/uni_links.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
|
||||
import 'package:cake_wallet/reactions/wallet_utils.dart';
|
||||
import 'package:cw_core/utils/socket_health_logger.dart';
|
||||
|
||||
class Root extends StatefulWidget {
|
||||
Root({
|
||||
@@ -33,6 +35,7 @@ class Root extends StatefulWidget {
|
||||
required this.linkViewModel,
|
||||
required this.tradeMonitor,
|
||||
required this.nodeSwitchingService,
|
||||
required this.trezorConnect,
|
||||
}) : super(key: key);
|
||||
|
||||
final AuthenticationStore authenticationStore;
|
||||
@@ -43,6 +46,7 @@ class Root extends StatefulWidget {
|
||||
final LinkViewModel linkViewModel;
|
||||
final TradeMonitor tradeMonitor;
|
||||
final NodeSwitchingService nodeSwitchingService;
|
||||
final TrezorConnect trezorConnect;
|
||||
|
||||
@override
|
||||
RootState createState() => RootState();
|
||||
@@ -110,6 +114,11 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||
|
||||
widget.linkViewModel.currentLink = uri;
|
||||
|
||||
if (uri.toString().startsWith(widget.trezorConnect.callbackBackUri)) {
|
||||
widget.trezorConnect.handleCallback(uri);
|
||||
return;
|
||||
}
|
||||
|
||||
bool requireAuth = await widget.authService.requireAuth();
|
||||
|
||||
if (!requireAuth && widget.authenticationStore.state == AuthenticationState.allowed) {
|
||||
|
||||
@@ -23,8 +23,7 @@ abstract class BaseBottomSheet extends StatelessWidget {
|
||||
this.leftActionButtonKey,
|
||||
this.rightActionButtonKey,
|
||||
required this.maxHeight,
|
||||
}) : assert(footerType == FooterType.none,
|
||||
'currentTheme is required unless footerType is none');
|
||||
});
|
||||
|
||||
final String titleText;
|
||||
final String? titleIconPath;
|
||||
|
||||
Reference in New Issue
Block a user