CW-1174: Add warning for sending to contract addresses (#2463)

* feat: add warning for sending to contract addresses

* feat: Add wallet type icon to full screen qr page
This commit is contained in:
David Adegoke
2025-08-19 18:30:07 +03:00
committed by GitHub
parent cb53840332
commit 09d10fce27
53 changed files with 616 additions and 240 deletions
+9 -7
View File
@@ -1,11 +1,13 @@
class QrViewData {
QrViewData({
this.version,
this.heroTag,
required this.data,
this.embeddedImagePath,
});
final int? version;
final String? heroTag;
final String data;
QrViewData({
this.version,
this.heroTag,
required this.data,
});
}
final String? embeddedImagePath;
}
+13
View File
@@ -32,4 +32,17 @@ bool isElectrumWallet(WalletType walletType) {
default:
return false;
}
}
bool hasTokens(WalletType walletType) {
switch (walletType) {
case WalletType.ethereum:
case WalletType.polygon:
case WalletType.solana:
case WalletType.tron:
case WalletType.zano:
return true;
default:
return false;
}
}
+119 -45
View File
@@ -5,13 +5,18 @@ import 'package:cake_wallet/src/widgets/address_text_field.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
import 'package:cake_wallet/src/widgets/checkbox_widget.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/src/widgets/warning_box_widget.dart';
import 'package:cake_wallet/themes/core/material_base_theme.dart';
import 'package:cake_wallet/themes/utils/custom_theme_colors.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -29,7 +34,9 @@ class EditTokenPage extends BasePage {
final String? initialContractAddress;
@override
String? get title => S.current.edit_token;
String? get title => (token != null || initialContractAddress != null)
? S.current.edit_token
: S.current.add_token;
@override
Widget body(BuildContext context) {
@@ -37,6 +44,7 @@ class EditTokenPage extends BasePage {
homeSettingsViewModel: homeSettingsViewModel,
token: token,
initialContractAddress: initialContractAddress,
currentTheme: currentTheme,
);
}
}
@@ -47,11 +55,13 @@ class EditTokenPageBody extends StatefulWidget {
required this.homeSettingsViewModel,
this.token,
this.initialContractAddress,
required this.currentTheme,
}) : super(key: key);
final HomeSettingsViewModel homeSettingsViewModel;
final CryptoCurrency? token;
final String? initialContractAddress;
final MaterialThemeBase currentTheme;
@override
State<EditTokenPageBody> createState() => _EditTokenPageBodyState();
@@ -74,6 +84,7 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
bool _showDisclaimer = false;
bool _disclaimerChecked = false;
bool isEditingToken = false;
bool _isTokenVerified = false;
@override
void initState() {
@@ -91,6 +102,8 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
_tokenIconPathController.text = widget.token?.iconPath ?? '';
isEditingToken = true;
_checkIfTokenIsVerified(address);
}
if (widget.initialContractAddress != null) {
@@ -112,6 +125,15 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
});
}
void _checkIfTokenIsVerified(String? contractAddress) async {
if (contractAddress != null) {
final isVerified = widget.homeSettingsViewModel.checkIfTokenIsWhitelisted(contractAddress);
setState(() {
_isTokenVerified = isVerified;
});
}
}
@override
Widget build(BuildContext context) {
return GestureDetector(
@@ -122,49 +144,26 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
padding: EdgeInsets.symmetric(horizontal: 25),
child: Column(
children: [
Container(
padding: EdgeInsets.symmetric(vertical: 16, horizontal: 28),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(12),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset('assets/images/restore_keys.png'),
const SizedBox(width: 24),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
S.of(context).warning,
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.w500,
),
),
Padding(
padding: EdgeInsets.only(top: 5),
child: Text(
S.of(context).add_token_warning,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
height: 1.6,
),
),
),
],
),
),
],
),
SizedBox(height: 30),
WarningBox(
padding: EdgeInsets.all(16),
content: S.of(context).add_token_warning,
currentTheme: widget.currentTheme,
showBorder: false,
textWeight: FontWeight.w500,
textAlign: TextAlign.start,
textColor: widget.currentTheme.isDark
? CustomThemeColors.warningOutlineColorDark
: CustomThemeColors.warningOutlineColorLight,
iconSize: 22,
iconSpacing: 16,
),
SizedBox(height: 50),
_tokenForm(),
],
),
),
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 48),
bottomSection: Column(
children: [
if (_showDisclaimer) ...[
@@ -191,8 +190,12 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
Navigator.pop(context);
},
text: widget.token != null ? S.of(context).delete : S.of(context).cancel,
color: Theme.of(context).colorScheme.errorContainer,
textColor: Theme.of(context).colorScheme.onErrorContainer,
color: isEditingToken
? Theme.of(context).colorScheme.errorContainer
: Theme.of(context).colorScheme.surfaceContainer,
textColor: isEditingToken
? Theme.of(context).colorScheme.onErrorContainer
: Theme.of(context).colorScheme.primary,
),
),
SizedBox(width: 20),
@@ -341,6 +344,8 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
_tokenIconPathController.text = token.iconPath ?? '';
if (_tokenDecimalController.text.isEmpty || isZano)
_tokenDecimalController.text = token.decimals.toString();
_checkIfTokenIsVerified(_contractAddressController.text);
}
}
}
@@ -363,12 +368,56 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_tokenIconPathController.text.isEmpty
? DottedBorder(
borderType: BorderType.Circle,
dashPattern: [6, 4],
color: Theme.of(context).colorScheme.surfaceContainerHighest,
strokeWidth: 2,
radius: Radius.circular(15),
child: Container(width: 75, height: 75),
)
: Stack(
alignment: Alignment.center,
children: [
ClipOval(
child: CakeImageWidget(
imageUrl: _tokenIconPathController.text,
width: 75,
height: 75,
),
),
if (_isTokenVerified)
Positioned(
bottom: 0,
right: 0,
child: Container(
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary,
shape: BoxShape.circle,
border: Border.all(
color: Theme.of(context).colorScheme.surface,
width: 2,
),
),
child: Icon(
Icons.check,
size: 16,
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
],
),
SizedBox(height: 25),
AddressTextField(
controller: _contractAddressController,
focusNode: _contractAddressFocusNode,
placeholder: S.of(context).token_contract_address,
placeholder: S.of(context).contract_address,
copyImagePath: 'assets/images/copy.png',
options: [AddressTextFieldOption.paste],
validator: widget.homeSettingsViewModel.walletType == WalletType.zano
? null
@@ -377,7 +426,32 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
_pasteText();
},
),
const SizedBox(height: 8),
const SizedBox(height: 16),
isEditingToken
? WarningBox(
padding: EdgeInsets.all(16),
content: S.of(context).tokens_strong_warning,
currentTheme: widget.currentTheme,
showBorder: false,
textWeight: FontWeight.w500,
textColor: widget.currentTheme.isDark
? CustomThemeColors.warningOutlineColorDark
: CustomThemeColors.warningOutlineColorLight,
showIcon: false,
)
: Text(
S.of(context).tokens_strong_warning,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.onSurface,
),
),
const SizedBox(height: 24),
Divider(
color: Theme.of(context).colorScheme.surfaceContainerHighest,
height: 1,
),
const SizedBox(height: 24),
BaseTextFormField(
controller: _tokenNameController,
focusNode: _tokenNameFocusNode,
@@ -392,7 +466,7 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
return S.of(context).field_required;
},
),
const SizedBox(height: 8),
const SizedBox(height: 10),
BaseTextFormField(
controller: _tokenSymbolController,
focusNode: _tokenSymbolFocusNode,
@@ -407,7 +481,7 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
return S.of(context).field_required;
},
),
const SizedBox(height: 8),
const SizedBox(height: 10),
BaseTextFormField(
controller: _tokenDecimalController,
focusNode: _tokenDecimalFocusNode,
@@ -4,6 +4,7 @@ import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
import 'package:cw_core/receive_page_option.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
import 'package:cake_wallet/src/widgets/gradient_background.dart';
@@ -61,8 +62,7 @@ class AddressPage extends BasePage {
color: titleColor(context),
size: 16,
);
final _closeButton =
currentTheme.isDark ? closeButtonImageDarkTheme : closeButtonImage;
final _closeButton = currentTheme.isDark ? closeButtonImageDarkTheme : closeButtonImage;
bool isMobileView = responsiveLayoutUtil.shouldRenderMobileUI;
@@ -171,6 +171,69 @@ class AddressPage extends BasePage {
}
},
),
if (addressListViewModel.hasTokensList) ...[
Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
border: Border.all(color: Theme.of(context).colorScheme.surfaceContainer),
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(20),
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CakeImageWidget(
imageUrl: addressListViewModel.monoImage,
height: 16,
width: 16,
),
SizedBox(width: 10),
Text(
'${S.current.your} ${addressListViewModel.walletTypeName} ${S.current.address}',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w500,
),
),
],
),
SizedBox(height: 10),
Text(
'${S.current.qr_instruction} ${addressListViewModel.walletTypeName}',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
fontWeight: FontWeight.w500,
),
),
SizedBox(height: 20),
Center(
child: SizedBox(
height: 40,
width: addressListViewModel.walletImages.length * 30.0,
child: Stack(
children: [
for (int i = addressListViewModel.walletImages.length - 1; i >= 0; i--)
Positioned(
left: i * 25.0,
child: ClipOval(
child: CakeImageWidget(
height: 35,
width: 35,
imageUrl: addressListViewModel.walletImages[i],
),
),
),
],
),
),
),
],
),
),
SizedBox(height: 48),
],
],
),
),
@@ -70,7 +70,11 @@ class FullscreenQRPage extends BasePage {
color: Theme.of(context).colorScheme.surface,
),
),
child: QrImage(data: qrViewData.data, version: qrViewData.version),
child: QrImage(
data: qrViewData.data,
version: qrViewData.version,
embeddedImagePath: qrViewData.embeddedImagePath,
),
),
),
),
@@ -1,4 +1,3 @@
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:flutter/material.dart';
import 'package:qr_flutter/qr_flutter.dart' as qr;
@@ -10,6 +9,7 @@ class QrImage extends StatelessWidget {
this.size = 100.0,
this.version,
this.errorCorrectionLevel = qr.QrErrorCorrectLevel.H,
this.embeddedImagePath,
});
final double size;
@@ -18,6 +18,7 @@ class QrImage extends StatelessWidget {
final String data;
final int? version;
final int errorCorrectionLevel;
final String? embeddedImagePath;
@override
Widget build(BuildContext context) {
@@ -29,7 +30,7 @@ class QrImage extends StatelessWidget {
foregroundColor: foregroundColor,
backgroundColor: backgroundColor,
padding: const EdgeInsets.all(8.0),
embeddedImage: AssetImage('assets/images/qr-cake.png'),
embeddedImage: AssetImage(embeddedImagePath ?? 'assets/images/qr-cake.png'),
);
}
}
+7 -10
View File
@@ -63,21 +63,12 @@ class QRWidget extends StatelessWidget {
children: <Widget>[
Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Text(
S.of(context).qr_fullscreen,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w500,
),
),
),
Row(
children: <Widget>[
Spacer(flex: 3),
Observer(
builder: (_) => Flexible(
flex: 5,
flex: 9,
child: GestureDetector(
onTap: () {
BrightnessUtil.changeBrightnessForFunction(
@@ -86,6 +77,7 @@ class QRWidget extends StatelessWidget {
context,
Routes.fullscreenQR,
arguments: QrViewData(
embeddedImagePath: addressListViewModel.qrImage,
data: addressUri.toString(),
heroTag: heroTag,
),
@@ -106,10 +98,15 @@ class QRWidget extends StatelessWidget {
child: Column(
children: [
Container(
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.5),
),
padding: EdgeInsets.all(3),
child: AspectRatio(
aspectRatio: 1.0,
child: QrImage(
embeddedImagePath: addressListViewModel.qrImage,
data: addressUri.toString(),
),
),
+3 -1
View File
@@ -36,6 +36,7 @@ class AddressTextField<T extends Currency> extends StatelessWidget {
this.hasUnderlineBorder = false,
this.borderWidth = 1.0,
this.contentPadding,
this.copyImagePath,
});
static const prefixIconWidth = 34.0;
@@ -60,6 +61,7 @@ class AddressTextField<T extends Currency> extends StatelessWidget {
final FocusNode? focusNode;
final T? selectedCurrency;
final Key? addressKey;
final String? copyImagePath;
final Function(BuildContext context)? onPushPasteButton;
final Function(BuildContext context)? onPushAddressBookButton;
@@ -125,7 +127,7 @@ class AddressTextField<T extends Currency> extends StatelessWidget {
borderRadius: BorderRadius.all(Radius.circular(6)),
),
child: Image.asset(
'assets/images/paste_ios.png',
copyImagePath ?? 'assets/images/paste_ios.png',
color: iconColor ?? Theme.of(context).colorScheme.onSurfaceVariant,
),
),
+39 -16
View File
@@ -3,42 +3,65 @@ import 'package:cake_wallet/themes/utils/custom_theme_colors.dart';
import 'package:flutter/material.dart';
class WarningBox extends StatelessWidget {
const WarningBox({required this.content, required this.currentTheme, Key? key}) : super(key: key);
const WarningBox({
required this.content,
required this.currentTheme,
this.showBorder = true,
this.textColor,
this.textAlign,
this.iconSize,
this.padding,
this.iconSpacing,
this.textWeight,
this.showIcon = true,
super.key,
});
final String content;
final MaterialThemeBase currentTheme;
final bool showBorder;
final Color? textColor;
final TextAlign? textAlign;
final double? iconSize;
final EdgeInsets? padding;
final double? iconSpacing;
final FontWeight? textWeight;
final bool showIcon;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
padding: padding ?? EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: currentTheme.isDark
? CustomThemeColors.warningContainerColorDark
: CustomThemeColors.warningContainerColorLight,
borderRadius: BorderRadius.all(Radius.circular(12)),
border: Border.all(
color: currentTheme.isDark
? CustomThemeColors.warningOutlineColorDark
: CustomThemeColors.warningOutlineColorLight,
width: 2.0,
),
border: showBorder
? Border.all(
color: currentTheme.isDark
? CustomThemeColors.warningOutlineColorDark
: CustomThemeColors.warningOutlineColorLight,
width: 2.0,
)
: null,
),
child: Row(
children: [
Icon(
Icons.warning_amber_rounded,
size: 64,
color: Theme.of(context).colorScheme.onSurface,
if (showIcon)
Icon(
Icons.warning_amber_rounded,
size: iconSize ?? 64,
color: textColor ?? Theme.of(context).colorScheme.onSurface,
),
SizedBox(width: 6),
SizedBox(width:iconSpacing ?? 6),
Expanded(
child: Text(
content,
textAlign: TextAlign.center,
textAlign: textAlign ?? TextAlign.center,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.w800,
color: Theme.of(context).colorScheme.onSurface,
fontWeight: textWeight ?? FontWeight.w800,
color: textColor ?? Theme.of(context).colorScheme.onSurface,
),
),
),
@@ -11,6 +11,7 @@ import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/reactions/wallet_utils.dart';
import 'package:cake_wallet/solana/solana.dart';
import 'package:cake_wallet/decred/decred.dart';
import 'package:cake_wallet/store/app_store.dart';
@@ -322,15 +323,12 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
WalletAddressListItem(address: wallet.walletAddresses.address, isPrimary: false);
@computed
String get payjoinEndpoint => wallet.type == WalletType.bitcoin
? bitcoin!.getPayjoinEndpoint(wallet)
: "";
String get payjoinEndpoint =>
wallet.type == WalletType.bitcoin ? bitcoin!.getPayjoinEndpoint(wallet) : "";
@computed
bool get isPayjoinUnavailable =>
wallet.type == WalletType.bitcoin &&
_settingsStore.usePayjoin &&
payjoinEndpoint.isEmpty;
wallet.type == WalletType.bitcoin && _settingsStore.usePayjoin && payjoinEndpoint.isEmpty;
@computed
PaymentURI get uri {
@@ -340,10 +338,7 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
case WalletType.haven:
return HavenURI(amount: amount, address: address.address);
case WalletType.bitcoin:
return BitcoinURI(
amount: amount,
address: address.address,
pjUri: payjoinEndpoint);
return BitcoinURI(amount: amount, address: address.address, pjUri: payjoinEndpoint);
case WalletType.litecoin:
return LitecoinURI(amount: amount, address: address.address);
case WalletType.ethereum:
@@ -363,7 +358,7 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
case WalletType.wownero:
return WowneroURI(amount: amount, address: address.address);
case WalletType.zano:
return ZanoURI(amount: amount, address: address.address);
return ZanoURI(amount: amount, address: address.address);
case WalletType.decred:
return DecredURI(amount: amount, address: address.address);
case WalletType.dogecoin:
@@ -511,8 +506,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
if (wallet.type == WalletType.decred) {
final addrInfos = decred!.getAddressInfos(wallet);
addrInfos.forEach((info) {
addressList.add(new WalletAddressListItem(isPrimary: false, address: info.address,
name: info.label));
addressList.add(
new WalletAddressListItem(isPrimary: false, address: info.address, name: info.label));
});
}
@@ -596,6 +591,12 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
return '';
}
@computed
bool get hasTokensList => hasTokens(type);
@computed
String get walletTypeName => walletTypeToString(type);
@computed
bool get hasAddressList => [
WalletType.monero,
@@ -609,8 +610,92 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
].contains(wallet.type);
@computed
bool get isElectrumWallet =>
[WalletType.bitcoin, WalletType.litecoin, WalletType.bitcoinCash, WalletType.dogecoin].contains(wallet.type);
bool get isElectrumWallet => [
WalletType.bitcoin,
WalletType.litecoin,
WalletType.bitcoinCash,
WalletType.dogecoin
].contains(wallet.type);
@computed
List<String> get walletImages {
switch (wallet.type) {
case WalletType.ethereum:
return [
'assets/images/eth_icon.png',
'assets/images/usdc_icon.png',
'assets/images/usdt_wallet_icon.png',
'assets/images/deuro_icon.png',
'assets/images/more_tokens.png',
];
case WalletType.solana:
return [
'assets/images/sol_icon.png',
'assets/images/usdc_icon.png',
'assets/images/usdt_wallet_icon.png',
'assets/images/more_tokens.png',
];
case WalletType.polygon:
return [
'assets/images/pol_icon.png',
'assets/images/eth_pol_icon.png',
'assets/images/usdc_icon.png',
'assets/images/usdt_wallet_icon.png',
'assets/images/more_tokens.png',
];
case WalletType.tron:
return [
'assets/images/trx_icon.png',
'assets/images/usdc_icon.png',
'assets/images/usdt_wallet_icon.png',
'assets/images/more_tokens.png',
];
case WalletType.zano:
return [
'assets/images/zano_bg_icon.png',
'assets/images/more_tokens.png',
];
default:
return [];
}
}
@computed
String get qrImage {
switch (type) {
case WalletType.ethereum:
return 'assets/images/eth_chain_qr.png';
case WalletType.solana:
return 'assets/images/sol_chain_qr.png';
case WalletType.polygon:
return 'assets/images/pol_chain_qr.png';
case WalletType.tron:
return 'assets/images/trx_chain_qr.png';
case WalletType.zano:
return 'assets/images/zano_chain_qr.png';
default:
return 'assets/images/qr-cake.png';
}
}
@computed
String get monoImage {
switch (type) {
case WalletType.ethereum:
return 'assets/images/eth_chain_mono.png';
case WalletType.solana:
return 'assets/images/sol_chain_mono.png';
case WalletType.polygon:
return 'assets/images/pol_chain_mono.png';
case WalletType.tron:
return 'assets/images/trx_chain_mono.png';
case WalletType.zano:
return 'assets/images/zano_chain_mono.png';
default:
return 'assets/images/eth_chain_mono.png';
}
}
@computed
bool get isBalanceAvailable => isElectrumWallet;