Generic Fixes (#1122)

* Fix Hive issue

* Disable RobinHood for Nano

* Validate context is still mounted [skip ci]

* Disable Exolix for new exchanges
Remove duplicate ethereum case

* add nano/banano to manifest/info.plist

* fix qr code issues for nano

* Add Nano-wallet to restore form qr
Add iOS keychain accessibility config

* support app links for ethereum and nano [skip ci]

* catch exceptions from gas price and estimated gas

* Add bitcoin cash to app links
Fix restore from QR for bitcoin cash

* Fixate bottom buttons for create/restore wallet in wallet list page

---------

Co-authored-by: fosse <matt.cfosse@gmail.com>
This commit is contained in:
Omar Hatem 2023-10-13 14:49:00 +03:00 committed by GitHub
parent 66301ff247
commit 426ac99e34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 275 additions and 188 deletions

View file

@ -52,6 +52,15 @@
<data android:scheme="litecoin" /> <data android:scheme="litecoin" />
<data android:scheme="litecoin-wallet" /> <data android:scheme="litecoin-wallet" />
<data android:scheme="litecoin_wallet" /> <data android:scheme="litecoin_wallet" />
<data android:scheme="ethereum" />
<data android:scheme="ethereum-wallet" />
<data android:scheme="ethereum_wallet" />
<data android:scheme="nano" />
<data android:scheme="nano-wallet" />
<data android:scheme="nano_wallet" />
<data android:scheme="bitcoincash" />
<data android:scheme="bitcoincash-wallet" />
<data android:scheme="bitcoincash_wallet" />
</intent-filter> </intent-filter>
</activity> </activity>
<meta-data <meta-data

View file

@ -42,13 +42,21 @@ class EthereumClient {
await _client!.getBalance(address); await _client!.getBalance(address);
Future<int> getGasUnitPrice() async { Future<int> getGasUnitPrice() async {
try {
final gasPrice = await _client!.getGasPrice(); final gasPrice = await _client!.getGasPrice();
return gasPrice.getInWei.toInt(); return gasPrice.getInWei.toInt();
} catch (_) {
return 0;
}
} }
Future<int> getEstimatedGas() async { Future<int> getEstimatedGas() async {
try {
final estimatedGas = await _client!.estimateGas(); final estimatedGas = await _client!.estimateGas();
return estimatedGas.toInt(); return estimatedGas.toInt();
} catch (_) {
return 0;
}
} }
Future<PendingEthereumTransaction> signTransaction({ Future<PendingEthereumTransaction> signTransaction({

View file

@ -100,6 +100,66 @@
<string>litecoin-wallet</string> <string>litecoin-wallet</string>
</array> </array>
</dict> </dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>ethereum</string>
<key>CFBundleURLSchemes</key>
<array>
<string>ethereum</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLName</key>
<string>ethereum-wallet</string>
<key>CFBundleURLSchemes</key>
<array>
<string>ethereum-wallet</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>nano</string>
<key>CFBundleURLSchemes</key>
<array>
<string>nano</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLName</key>
<string>nano-wallet</string>
<key>CFBundleURLSchemes</key>
<array>
<string>nano-wallet</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>bitcoincash</string>
<key>CFBundleURLSchemes</key>
<array>
<string>bitcoincash</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLName</key>
<string>bitcoincash-wallet</string>
<key>CFBundleURLSchemes</key>
<array>
<string>bitcoincash-wallet</string>
</array>
</dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>

View file

@ -53,8 +53,6 @@ class MainActions {
case WalletType.litecoin: case WalletType.litecoin:
case WalletType.ethereum: case WalletType.ethereum:
case WalletType.bitcoinCash: case WalletType.bitcoinCash:
case WalletType.nano:
case WalletType.banano:
switch (defaultBuyProvider) { switch (defaultBuyProvider) {
case BuyProviderType.AskEachTime: case BuyProviderType.AskEachTime:
Navigator.pushNamed(context, Routes.buy); Navigator.pushNamed(context, Routes.buy);
@ -67,6 +65,8 @@ class MainActions {
break; break;
} }
break; break;
case WalletType.nano:
case WalletType.banano:
case WalletType.monero: case WalletType.monero:
await getIt.get<OnRamperBuyProvider>().launchProvider(context); await getIt.get<OnRamperBuyProvider>().launchProvider(context);
break; break;

View file

@ -97,7 +97,7 @@ Future<void> initializeAppConfigs() async {
CakeHive.registerAdapter(WalletInfoAdapter()); CakeHive.registerAdapter(WalletInfoAdapter());
} }
if (!Hive.isAdapterRegistered(DERIVATION_TYPE_TYPE_ID)) { if (!CakeHive.isAdapterRegistered(DERIVATION_TYPE_TYPE_ID)) {
CakeHive.registerAdapter(DerivationTypeAdapter()); CakeHive.registerAdapter(DerivationTypeAdapter());
} }
@ -125,14 +125,17 @@ Future<void> initializeAppConfigs() async {
CakeHive.registerAdapter(AnonpayInvoiceInfoAdapter()); CakeHive.registerAdapter(AnonpayInvoiceInfoAdapter());
} }
final secureStorage = FlutterSecureStorage(); final secureStorage = FlutterSecureStorage(
iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
);
final transactionDescriptionsBoxKey = final transactionDescriptionsBoxKey =
await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey); await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey); final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
final ordersBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Order.boxKey); final ordersBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Order.boxKey);
final contacts = await CakeHive.openBox<Contact>(Contact.boxName); final contacts = await CakeHive.openBox<Contact>(Contact.boxName);
final nodes = await CakeHive.openBox<Node>(Node.boxName); final nodes = await CakeHive.openBox<Node>(Node.boxName);
final powNodes = await CakeHive.openBox<Node>(Node.boxName + "pow");// must be different from Node.boxName final powNodes =
await CakeHive.openBox<Node>(Node.boxName + "pow"); // must be different from Node.boxName
final transactionDescriptions = await CakeHive.openBox<TransactionDescription>( final transactionDescriptions = await CakeHive.openBox<TransactionDescription>(
TransactionDescription.boxName, TransactionDescription.boxName,
encryptionKey: transactionDescriptionsBoxKey); encryptionKey: transactionDescriptionsBoxKey);

View file

@ -194,8 +194,10 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
contractAddress: _contractAddressController.text, contractAddress: _contractAddressController.text,
decimal: int.parse(_tokenDecimalController.text), decimal: int.parse(_tokenDecimalController.text),
)); ));
if (context.mounted) {
Navigator.pop(context); Navigator.pop(context);
} }
}
}, },
text: S.of(context).save, text: S.of(context).save,
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,

View file

@ -5,7 +5,6 @@ import 'package:cake_wallet/utils/request_review_handler.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/execution_state.dart'; import 'package:cake_wallet/core/execution_state.dart';
@ -26,16 +25,15 @@ import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
void showInformation( void showInformation(
ExchangeTradeViewModel exchangeTradeViewModel, BuildContext context) { ExchangeTradeViewModel exchangeTradeViewModel, BuildContext context) {
final fetchingLabel = S.current.fetching;
final trade = exchangeTradeViewModel.trade; final trade = exchangeTradeViewModel.trade;
final walletName = exchangeTradeViewModel.wallet.name; final walletName = exchangeTradeViewModel.wallet.name;
final information = exchangeTradeViewModel.isSendable final information = exchangeTradeViewModel.isSendable
? S.current.exchange_result_confirm( ? S.current.exchange_result_confirm(
trade.amount ?? fetchingLabel, trade.from.toString(), walletName) + trade.amount, trade.from.toString(), walletName) +
exchangeTradeViewModel.extraInfo exchangeTradeViewModel.extraInfo
: S.current.exchange_result_description( : S.current.exchange_result_description(
trade.amount ?? fetchingLabel, trade.from.toString()) + trade.amount, trade.from.toString()) +
exchangeTradeViewModel.extraInfo; exchangeTradeViewModel.extraInfo;
showPopUp<void>( showPopUp<void>(
@ -177,7 +175,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
), ),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = widget.exchangeTradeViewModel.items[index]; final item = widget.exchangeTradeViewModel.items[index];
final value = item.data ?? fetchingLabel; final value = item.data;
final content = ListRow( final content = ListRow(
title: item.title, title: item.title,

View file

@ -13,7 +13,6 @@ import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart'; import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
@ -65,13 +64,13 @@ class WalletListBodyState extends State<WalletListBody> {
return Container( return Container(
padding: EdgeInsets.only(top: 16), padding: EdgeInsets.only(top: 16),
child: ScrollableWithBottomSection( child: Column(
contentPadding: EdgeInsets.only(bottom: 20), children: [
content: Container( Expanded(
child: Container(
child: Observer( child: Observer(
builder: (_) => ListView.separated( builder: (_) => ListView.separated(
shrinkWrap: true, physics: const BouncingScrollPhysics(),
physics: const NeverScrollableScrollPhysics(),
separatorBuilder: (_, index) => separatorBuilder: (_, index) =>
Divider(color: Theme.of(context).colorScheme.background, height: 32), Divider(color: Theme.of(context).colorScheme.background, height: 32),
itemCount: widget.walletListViewModel.wallets.length, itemCount: widget.walletListViewModel.wallets.length,
@ -94,7 +93,8 @@ class WalletListBodyState extends State<WalletListBody> {
width: 4, width: 4,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topRight: Radius.circular(4), bottomRight: Radius.circular(4)), topRight: Radius.circular(4),
bottomRight: Radius.circular(4)),
color: currentColor), color: currentColor),
), ),
Expanded( Expanded(
@ -106,7 +106,9 @@ class WalletListBodyState extends State<WalletListBody> {
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
wallet.isEnabled ? _imageFor(type: wallet.type) : nonWalletTypeIcon, wallet.isEnabled
? _imageFor(type: wallet.type)
: nonWalletTypeIcon,
SizedBox(width: 10), SizedBox(width: 10),
Flexible( Flexible(
child: Text( child: Text(
@ -116,8 +118,9 @@ class WalletListBodyState extends State<WalletListBody> {
style: TextStyle( style: TextStyle(
fontSize: 22, fontSize: 22,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: color: Theme.of(context)
Theme.of(context).extension<CakeTextTheme>()!.titleColor, .extension<CakeTextTheme>()!
.titleColor,
), ),
), ),
), ),
@ -154,8 +157,9 @@ class WalletListBodyState extends State<WalletListBody> {
child: Icon( child: Icon(
Icons.edit, Icons.edit,
size: 14, size: 14,
color: color: Theme.of(context)
Theme.of(context).extension<ReceivePageTheme>()!.iconsColor, .extension<ReceivePageTheme>()!
.iconsColor,
), ),
), ),
), ),
@ -167,8 +171,10 @@ class WalletListBodyState extends State<WalletListBody> {
), ),
), ),
), ),
bottomSectionPadding: EdgeInsets.only(bottom: 24, right: 24, left: 24), ),
bottomSection: Column( Padding(
padding: const EdgeInsets.all(24),
child: Column(
children: <Widget>[ children: <Widget>[
PrimaryImageButton( PrimaryImageButton(
onPressed: () { onPressed: () {
@ -229,6 +235,8 @@ class WalletListBodyState extends State<WalletListBody> {
], ],
), ),
), ),
],
),
); );
} }

View file

@ -161,7 +161,7 @@ class ExceptionHandler {
"Handshake error in client", "Handshake error in client",
"Error while launching http", "Error while launching http",
"OS Error: Network is unreachable", "OS Error: Network is unreachable",
"ClientException: Write failed, uri=https:", "ClientException: Write failed, uri=http",
]; ];
static Future<void> _addDeviceInfo(File file) async { static Future<void> _addDeviceInfo(File file) async {

View file

@ -1,3 +1,4 @@
class FeatureFlag { class FeatureFlag {
static const bool isCakePayEnabled = false; static const bool isCakePayEnabled = false;
static const bool isExolixEnabled = false;
} }

View file

@ -17,12 +17,14 @@ class PaymentRequest {
} }
if (nano != null) { if (nano != null) {
if (amount.isNotEmpty) {
if (address.contains("nano")) { if (address.contains("nano")) {
amount = nanoUtil!.getRawAsUsableString(amount, nanoUtil!.rawPerNano); amount = nanoUtil!.getRawAsUsableString(amount, nanoUtil!.rawPerNano);
} else if (address.contains("ban")) { } else if (address.contains("ban")) {
amount = nanoUtil!.getRawAsUsableString(amount, nanoUtil!.rawPerBanano); amount = nanoUtil!.getRawAsUsableString(amount, nanoUtil!.rawPerBanano);
} }
} }
}
return PaymentRequest(address, amount, note, scheme); return PaymentRequest(address, amount, note, scheme);
} }

View file

@ -97,13 +97,6 @@ class TransactionListItem extends ActionListItem with Keyable {
nano!.getTransactionAmountRaw(transaction).toString(), nanoUtil!.rawPerNano)), nano!.getTransactionAmountRaw(transaction).toString(), nanoUtil!.rawPerNano)),
price: price); price: price);
break; break;
case WalletType.ethereum:
final asset = ethereum!.assetOfTransaction(balanceViewModel.wallet, transaction);
final price = balanceViewModel.fiatConvertationStore.prices[asset];
amount = calculateFiatAmountRaw(
cryptoAmount: ethereum!.formatterEthereumAmountToDouble(transaction: transaction),
price: price);
break;
default: default:
break; break;
} }

View file

@ -16,6 +16,7 @@ import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dar
import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart'; import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart';
import 'package:cake_wallet/exchange/trocador/trocador_exchange_provider.dart'; import 'package:cake_wallet/exchange/trocador/trocador_exchange_provider.dart';
import 'package:cake_wallet/exchange/trocador/trocador_request.dart'; import 'package:cake_wallet/exchange/trocador/trocador_request.dart';
import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart'; import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/app_store.dart';
@ -154,7 +155,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
SideShiftExchangeProvider(), SideShiftExchangeProvider(),
SimpleSwapExchangeProvider(), SimpleSwapExchangeProvider(),
TrocadorExchangeProvider(useTorOnly: _useTorOnly), TrocadorExchangeProvider(useTorOnly: _useTorOnly),
ExolixExchangeProvider(), if (FeatureFlag.isExolixEnabled) ExolixExchangeProvider(),
]; ];
@observable @observable

View file

@ -73,10 +73,12 @@ class WalletRestoreFromQRCode {
case 'litecoin-wallet': case 'litecoin-wallet':
return WalletType.litecoin; return WalletType.litecoin;
case 'bitcoincash': case 'bitcoincash':
case 'bitcoinCash-wallet': case 'bitcoincash-wallet':
return WalletType.bitcoinCash; return WalletType.bitcoinCash;
case 'ethereum':
case 'ethereum-wallet': case 'ethereum-wallet':
return WalletType.ethereum; return WalletType.ethereum;
case 'nano':
case 'nano-wallet': case 'nano-wallet':
return WalletType.nano; return WalletType.nano;
default: default:

View file

@ -148,7 +148,7 @@ abstract class WalletKeysViewModelBase with Store {
case WalletType.ethereum: case WalletType.ethereum:
return 'ethereum-wallet'; return 'ethereum-wallet';
case WalletType.bitcoinCash: case WalletType.bitcoinCash:
return 'bitcoinCash-wallet'; return 'bitcoincash-wallet';
case WalletType.nano: case WalletType.nano:
return 'nano-wallet'; return 'nano-wallet';
case WalletType.banano: case WalletType.banano: