mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
Merge branch 'refs/heads/dev' into cw-1440-new-buy-sell-flow
This commit is contained in:
@@ -631,6 +631,7 @@ class CakePayBuyCardPage extends BasePage {
|
||||
amountValue: _sendViewModel.amountParsingProxy
|
||||
.asDisplayStringWithSymbol(_sendViewModel.pendingTransaction!.amount),
|
||||
quantity: 'QTY: ${cakePayBuyCardViewModel.quantity}',
|
||||
explanation: _sendViewModel.pendingTransactionAdditionalCostNotice,
|
||||
fiatAmountValue: _sendViewModel.pendingTransactionFiatAmountFormatted,
|
||||
fee: S.of(bottomSheetContext).send_fee,
|
||||
feeValue: _sendViewModel.amountParsingProxy
|
||||
|
||||
@@ -86,6 +86,7 @@ class WalletCreationService {
|
||||
case WalletType.dogecoin:
|
||||
case WalletType.nano:
|
||||
case WalletType.zcash:
|
||||
case WalletType.decred:
|
||||
return true;
|
||||
case WalletType.monero:
|
||||
case WalletType.wownero:
|
||||
@@ -93,7 +94,6 @@ class WalletCreationService {
|
||||
case WalletType.haven:
|
||||
case WalletType.banano:
|
||||
case WalletType.zano:
|
||||
case WalletType.decred:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,26 @@ class CWDecred extends Decred {
|
||||
|
||||
@override
|
||||
WalletCredentials createDecredNewWalletCredentials(
|
||||
{required String name, WalletInfo? walletInfo}) =>
|
||||
DecredNewWalletCredentials(name: name, walletInfo: walletInfo);
|
||||
{required String name,
|
||||
String? password,
|
||||
String? passphrase,
|
||||
String? mnemonic,
|
||||
WalletInfo? walletInfo}) =>
|
||||
DecredNewWalletCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
passphrase: passphrase,
|
||||
mnemonic: mnemonic,
|
||||
walletInfo: walletInfo);
|
||||
|
||||
@override
|
||||
WalletCredentials createDecredRestoreWalletFromSeedCredentials(
|
||||
{required String name, required String mnemonic, required String password}) =>
|
||||
DecredRestoreWalletFromSeedCredentials(name: name, mnemonic: mnemonic, password: password);
|
||||
{required String name,
|
||||
required String mnemonic,
|
||||
required String password,
|
||||
String? passphrase}) =>
|
||||
DecredRestoreWalletFromSeedCredentials(
|
||||
name: name, mnemonic: mnemonic, password: password, passphrase: passphrase);
|
||||
|
||||
@override
|
||||
WalletCredentials createDecredRestoreWalletFromPubkeyCredentials(
|
||||
@@ -19,8 +32,8 @@ class CWDecred extends Decred {
|
||||
DecredRestoreWalletFromPubkeyCredentials(name: name, pubkey: pubkey, password: password);
|
||||
|
||||
@override
|
||||
WalletService createDecredWalletService(Box<UnspentCoinsInfo> unspentCoinSource) =>
|
||||
DecredWalletService(unspentCoinSource);
|
||||
WalletService createDecredWalletService(Box<UnspentCoinsInfo> unspentCoinSource, bool isDirect) =>
|
||||
DecredWalletService(unspentCoinSource, isDirect);
|
||||
|
||||
@override
|
||||
List<TransactionPriority> getTransactionPriorities() => DecredTransactionPriority.all;
|
||||
|
||||
+2
-1
@@ -1347,7 +1347,8 @@ Future<void> setup({
|
||||
case WalletType.zano:
|
||||
return zano!.createZanoWalletService();
|
||||
case WalletType.decred:
|
||||
return decred!.createDecredWalletService(_unspentCoinsInfoSource);
|
||||
return decred!.createDecredWalletService(
|
||||
_unspentCoinsInfoSource, SettingsStoreBase.walletPasswordDirectInput);
|
||||
case WalletType.haven:
|
||||
return HavenWalletService();
|
||||
case WalletType.zcash:
|
||||
|
||||
@@ -95,8 +95,12 @@ Future<void> defaultSettingsMigration(
|
||||
case 1:
|
||||
await sharedPreferences.setString(
|
||||
PreferencesKey.currentFiatCurrencyKey, FiatCurrency.usd.toString());
|
||||
await sharedPreferences.setInt(PreferencesKey.currentTransactionPriorityKeyLegacy,
|
||||
monero!.getDefaultTransactionPriority().raw);
|
||||
|
||||
if (monero != null) {
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentTransactionPriorityKeyLegacy,
|
||||
monero!.getDefaultTransactionPriority().raw);
|
||||
}
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentBalanceDisplayModeKey, BalanceDisplayMode.availableBalance.raw);
|
||||
await sharedPreferences.setBool('save_recipient_address', true);
|
||||
@@ -791,6 +795,10 @@ Future<void> _backupWowneroSeeds(Box<HavenSeedStore> havenSeedStore) async {
|
||||
}
|
||||
|
||||
Future<void> _updateMoneroPriority(SharedPreferences sharedPreferences) async {
|
||||
if (monero == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final currentPriority =
|
||||
await sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority) ??
|
||||
monero!.getDefaultTransactionPriority().serialize();
|
||||
@@ -1071,11 +1079,15 @@ Future<void> generateBackupPassword(SecureStorage secureStorage) async {
|
||||
|
||||
Future<void> changeTransactionPriorityAndFeeRateKeys(SharedPreferences sharedPreferences) async {
|
||||
final legacyTransactionPriority =
|
||||
sharedPreferences.getInt(PreferencesKey.currentTransactionPriorityKeyLegacy)!;
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.moneroTransactionPriority, legacyTransactionPriority);
|
||||
await sharedPreferences.setInt(PreferencesKey.bitcoinTransactionPriority,
|
||||
bitcoin!.getMediumTransactionPriority().serialize());
|
||||
sharedPreferences.getInt(PreferencesKey.currentTransactionPriorityKeyLegacy);
|
||||
if (legacyTransactionPriority != null) {
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.moneroTransactionPriority, legacyTransactionPriority);
|
||||
}
|
||||
if (bitcoin != null) {
|
||||
await sharedPreferences.setInt(PreferencesKey.bitcoinTransactionPriority,
|
||||
bitcoin!.getMediumTransactionPriority().serialize());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fixBtcDerivationPaths() async {
|
||||
|
||||
@@ -63,7 +63,8 @@ class PreferencesKey {
|
||||
static const zanoTransactionPriority = 'current_fee_priority_zano';
|
||||
static const wowneroTransactionPriority = 'current_fee_priority_wownero';
|
||||
static const decredTransactionPriority = 'current_fee_priority_decred';
|
||||
static const zcashTransactionPriority = 'current_fee_priority_decred';
|
||||
static const zcashTransactionPriority = 'current_fee_priority_zcash';
|
||||
static const dogecoinTransactionPriority = 'current_fee_priority_dogecoin';
|
||||
static const customBitcoinFeeRate = 'custom_electrum_fee_rate';
|
||||
static const silentPaymentsCardDisplay = 'silentPaymentsCardDisplay';
|
||||
static const mwebCardDisplay = 'mwebCardDisplay';
|
||||
|
||||
@@ -138,6 +138,10 @@ class JupiterExchangeProvider extends ExchangeProvider {
|
||||
if (!_isSolanaCurrency(from) || !_isSolanaCurrency(to)) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if (amount <= 0) {
|
||||
return 0.0;
|
||||
}
|
||||
final inputMint = _getTokenMint(from);
|
||||
final outputMint = _getTokenMint(to);
|
||||
|
||||
|
||||
@@ -238,8 +238,14 @@ class _CardCustomizerState extends State<CardCustomizer> {
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
color: Theme.of(context).brightness ==
|
||||
Brightness.light
|
||||
? Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurfaceVariant
|
||||
.withAlpha(64)
|
||||
: Theme.of(context)
|
||||
.colorScheme
|
||||
.surfaceContainerHigh,
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
|
||||
@@ -215,12 +215,7 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
final _addressFocusNode = FocusNode();
|
||||
final _disposers = <ReactionDisposer>[];
|
||||
StreamSubscription<Uri>? _deepLinkSubscription;
|
||||
late final AnyPayFlow _anyPayFlow = AnyPayFlow(
|
||||
anyPayService: widget.anyPayService,
|
||||
sendViewModel: widget.sendViewModel,
|
||||
authService: widget.authService,
|
||||
walletSwitcherViewModel: widget.walletSwitcherViewModel,
|
||||
);
|
||||
late final AnyPayFlow _anyPayFlow;
|
||||
ContactRecord? newContactAddress;
|
||||
|
||||
bool _justHandledPasteButton = false;
|
||||
@@ -228,6 +223,12 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_anyPayFlow = AnyPayFlow(
|
||||
anyPayService: widget.anyPayService,
|
||||
sendViewModel: widget.sendViewModel,
|
||||
authService: widget.authService,
|
||||
walletSwitcherViewModel: widget.walletSwitcherViewModel,
|
||||
);
|
||||
_addInputControllers();
|
||||
|
||||
_disposers.add(
|
||||
|
||||
@@ -39,7 +39,9 @@ class HistoryModal extends StatelessWidget {
|
||||
child: Stack(
|
||||
children: [
|
||||
Material(
|
||||
child: CustomScrollView(controller: ModalScrollController.of(context), slivers: [
|
||||
child: CustomScrollView(physics: ClampingScrollPhysics(),
|
||||
controller: ModalScrollController.of(context),
|
||||
slivers: [
|
||||
HistorySection(
|
||||
detailsAsPage: true,
|
||||
dashboardViewModel: dashboardViewModel,
|
||||
|
||||
@@ -22,6 +22,7 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import "package:modal_bottom_sheet/modal_bottom_sheet.dart";
|
||||
|
||||
class HistorySection extends StatelessWidget {
|
||||
const HistorySection(
|
||||
@@ -107,8 +108,8 @@ class HistorySection extends StatelessWidget {
|
||||
Navigator.of(context).push(CupertinoPageRoute(
|
||||
builder: (context) => Material(child: page)));
|
||||
} else {
|
||||
showModalBottomSheet(
|
||||
isScrollControlled: true,
|
||||
showMaterialModalBottomSheet(
|
||||
backgroundColor: Colors.transparent,
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
FractionallySizedBox(heightFactor: 0.9, child: page));
|
||||
|
||||
@@ -100,9 +100,9 @@ class HistoryTile extends StatelessWidget {
|
||||
children: [
|
||||
Opacity(
|
||||
opacity: pending ? 0.5 : 1,
|
||||
child: CakeImageWidget(
|
||||
child: TokenImageWidget(
|
||||
imageUrl: asset?.iconPath ?? "",
|
||||
width: 34,
|
||||
size: 34,
|
||||
),
|
||||
),
|
||||
Align(
|
||||
|
||||
@@ -201,6 +201,7 @@ class SendTransactionDetails extends StatelessWidget {
|
||||
Widget _buildMainContent(BuildContext context) {
|
||||
return Observer(builder: (context) {
|
||||
final transaction = sendViewModel.pendingTransaction;
|
||||
final additionalCostNotice = sendViewModel.pendingTransactionAdditionalCostNotice;
|
||||
|
||||
final currencySymbol =
|
||||
sendViewModel.amountParsingProxy.getCryptoSymbol(sendViewModel.selectedCryptoCurrency);
|
||||
@@ -398,6 +399,26 @@ class SendTransactionDetails extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (additionalCostNotice != null) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Text(
|
||||
additionalCostNotice,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
if (sendViewModel.isElectrumWallet) ...[
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
|
||||
@@ -17,11 +17,11 @@ bool isBIP39Wallet(WalletType walletType) {
|
||||
case WalletType.monero:
|
||||
case WalletType.dogecoin:
|
||||
case WalletType.zcash:
|
||||
case WalletType.decred:
|
||||
return true;
|
||||
case WalletType.wownero:
|
||||
case WalletType.haven:
|
||||
case WalletType.zano:
|
||||
case WalletType.decred:
|
||||
case WalletType.none:
|
||||
return false;
|
||||
}
|
||||
@@ -32,6 +32,7 @@ bool isElectrumWallet(WalletType walletType) {
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoinCash:
|
||||
case WalletType.dogecoin:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@@ -130,11 +130,11 @@ class CWSolana extends Solana {
|
||||
|
||||
final token = (wallet as SolanaWallet).splTokenBySymbol(transaction.amount.currency.symbol);
|
||||
|
||||
if (token == null) {
|
||||
throw StateError('No SPL token for symbol ${transaction.amount.currency.symbol}');
|
||||
if (token != null) {
|
||||
return token;
|
||||
}
|
||||
|
||||
return token;
|
||||
return transaction.amount.currency as CryptoCurrency;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -276,6 +276,8 @@ class CWSolana extends Solana {
|
||||
'Jupiter swap returned unknown status: $status. Error: $errorMessage. Code: $errorCode',
|
||||
);
|
||||
}
|
||||
} on JupiterSwapFailedException {
|
||||
rethrow;
|
||||
} catch (e) {
|
||||
throw Exception('Failed to execute Jupiter swap: $e');
|
||||
}
|
||||
@@ -420,7 +422,9 @@ class CWSolana extends Solana {
|
||||
if (discoveredMints.isNotEmpty) {
|
||||
await wallet.updateSPLTokenTransactions(specificMints: discoveredMints);
|
||||
}
|
||||
} catch (_) {}
|
||||
} catch (e) {
|
||||
printV("Error discovering wallet tokens: ${e.toString()}");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -328,6 +328,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||
amount: S.of(bottomSheetContext).send_amount,
|
||||
amountValue: sendVM.amountParsingProxy
|
||||
.getDisplayCryptoAmount(amountValue, sendVM.selectedCryptoCurrency),
|
||||
explanation: sendVM.pendingTransactionAdditionalCostNotice,
|
||||
fiatAmountValue: fiatAmountValue,
|
||||
fee: isEVMCompatibleChain(sendVM.walletType)
|
||||
? S.of(bottomSheetContext).send_estimated_fee
|
||||
|
||||
@@ -11,6 +11,7 @@ import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/view_model/restore_from_backup_view_model.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import "package:flutter/services.dart";
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
@@ -180,8 +181,11 @@ class RestoreFromBackupPage extends BasePage {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
try {
|
||||
await restoreFromBackupViewModel.import(textEditingController.text);
|
||||
await SystemChannels.textInput.invokeMethod<void>("TextInput.hide");
|
||||
} on IncompatibleBackupAppException catch (e) {
|
||||
final isConfirmed = await showPopUp<bool>(
|
||||
context: context,
|
||||
|
||||
@@ -630,7 +630,7 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
||||
}
|
||||
|
||||
if ((walletRestoreViewModel.type == WalletType.decred) &&
|
||||
seedWords.length != WalletRestoreViewModelBase.decredSeedMnemonicLength) {
|
||||
![12, 15, 24].contains(seedWords.length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ class OtherSettingsPage extends BasePage {
|
||||
},
|
||||
}),
|
||||
),
|
||||
if(_otherSettingsViewModel.hasSignVerify)
|
||||
ListItemRegularRow(
|
||||
keyValue: "security_backup_page_sign_and_verify",
|
||||
label: S.of(context).sign_verify_title,
|
||||
@@ -152,10 +153,12 @@ class OtherSettingsPage extends BasePage {
|
||||
],
|
||||
if (_otherSettingsViewModel.walletType == WalletType.bitcoin)
|
||||
"btc_logging": [
|
||||
if(_otherSettingsViewModel.hasLightning)
|
||||
ListItemRegularRow(
|
||||
keyValue: "export_lightning_logs",
|
||||
label: S.of(context).export_lightning_logs,
|
||||
onTap: () => onExportLNLog(context)),
|
||||
if(_otherSettingsViewModel.hasPayjoin)
|
||||
ListItemRegularRow(
|
||||
keyValue: "export_payjoin_logs",
|
||||
label: S.of(context).export_payjoin_logs,
|
||||
|
||||
@@ -76,7 +76,7 @@ class PrivacyPage extends BasePage {
|
||||
}),
|
||||
],
|
||||
"": [
|
||||
if (_privacySettingsViewModel.isBitcoin)
|
||||
if (_privacySettingsViewModel.hasSilentPaymentsScanning)
|
||||
ListItemRegularRow(
|
||||
iconPath: "assets/new-ui/settings_row_icons/silent-payments.svg",
|
||||
keyValue: "silent_payments",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import "dart:async";
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:cake_wallet/di.dart';
|
||||
@@ -5,6 +6,7 @@ import 'package:cake_wallet/entities/calculate_fiat_amount.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import "package:cw_core/utils/print_verbose.dart";
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:eth_sig_util/eth_sig_util.dart';
|
||||
import 'package:eth_sig_util/util/utils.dart';
|
||||
@@ -18,6 +20,7 @@ import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wall
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/models/wc_connection_model.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/utils/eth_utils.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/utils/method_utils.dart';
|
||||
import "package:cake_wallet/src/screens/wallet_connect/widgets/bottom_sheet/bottom_sheet_message_display_widget.dart";
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/evm/evm.dart';
|
||||
@@ -82,7 +85,9 @@ class EvmChainServiceImpl {
|
||||
if (appStore.wallet != null && isEVMCompatibleChain(appStore.wallet!.type)) {
|
||||
final walletClient = evm?.getWeb3Client(appStore.wallet!);
|
||||
|
||||
if (walletClient != null) return walletClient;
|
||||
if (walletClient != null) {
|
||||
return walletClient;
|
||||
}
|
||||
}
|
||||
|
||||
final node = appStore.settingsStore.getCurrentNode(appStore.wallet!.type);
|
||||
@@ -93,8 +98,18 @@ class EvmChainServiceImpl {
|
||||
Future<void> personalSign(String topic, dynamic parameters) async {
|
||||
debugPrint('personalSign request: $parameters');
|
||||
|
||||
final pRequest = walletKit.pendingRequests.getAll().last;
|
||||
final pRequest = _pendingRequest(topic, EVMSupportedMethods.personalSign.name);
|
||||
if (pRequest == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final address = EthUtils.getAddressFromSessionRequest(pRequest);
|
||||
|
||||
if (!_isRequestAuthorized(topic, requestAddress: address)) {
|
||||
await _rejectUnauthorizedRequest(topic, pRequest.id);
|
||||
return;
|
||||
}
|
||||
|
||||
final data = EthUtils.getDataFromSessionRequest(pRequest);
|
||||
final message = EthUtils.getUtf8Message(data.toString());
|
||||
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
|
||||
@@ -104,6 +119,7 @@ class EvmChainServiceImpl {
|
||||
method: pRequest.method,
|
||||
chainId: pRequest.chainId,
|
||||
address: address,
|
||||
topic: topic,
|
||||
transportType: pRequest.transportType.name,
|
||||
verifyContext: pRequest.verifyContext,
|
||||
);
|
||||
@@ -141,8 +157,18 @@ class EvmChainServiceImpl {
|
||||
Future<void> ethSign(String topic, dynamic parameters) async {
|
||||
debugPrint('ethSign request: $parameters');
|
||||
|
||||
final pRequest = walletKit.pendingRequests.getAll().last;
|
||||
final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSign.name);
|
||||
if (pRequest == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final address = EthUtils.getAddressFromSessionRequest(pRequest);
|
||||
|
||||
if (!_isRequestAuthorized(topic, requestAddress: address)) {
|
||||
await _rejectUnauthorizedRequest(topic, pRequest.id);
|
||||
return;
|
||||
}
|
||||
|
||||
final data = EthUtils.getDataFromSessionRequest(pRequest);
|
||||
final message = EthUtils.getUtf8Message(data.toString());
|
||||
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
|
||||
@@ -152,6 +178,7 @@ class EvmChainServiceImpl {
|
||||
method: pRequest.method,
|
||||
chainId: pRequest.chainId,
|
||||
address: address,
|
||||
topic: topic,
|
||||
transportType: pRequest.transportType.name,
|
||||
verifyContext: pRequest.verifyContext,
|
||||
);
|
||||
@@ -189,8 +216,18 @@ class EvmChainServiceImpl {
|
||||
Future<void> ethSignTypedData(String topic, dynamic parameters) async {
|
||||
debugPrint('ethSignTypedData request: $parameters');
|
||||
|
||||
final pRequest = walletKit.pendingRequests.getAll().last;
|
||||
final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSignTypedData.name);
|
||||
if (pRequest == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final address = EthUtils.getAddressFromSessionRequest(pRequest);
|
||||
|
||||
if (!_isRequestAuthorized(topic, requestAddress: address)) {
|
||||
await _rejectUnauthorizedRequest(topic, pRequest.id);
|
||||
return;
|
||||
}
|
||||
|
||||
final data = EthUtils.getDataFromSessionRequest(pRequest) as String;
|
||||
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
|
||||
|
||||
@@ -199,6 +236,7 @@ class EvmChainServiceImpl {
|
||||
method: pRequest.method,
|
||||
chainId: pRequest.chainId,
|
||||
address: address,
|
||||
topic: topic,
|
||||
transportType: pRequest.transportType.name,
|
||||
verifyContext: pRequest.verifyContext,
|
||||
);
|
||||
@@ -236,8 +274,18 @@ class EvmChainServiceImpl {
|
||||
|
||||
final permitRequestMessage = await extractPermitData(parameters);
|
||||
|
||||
final pRequest = walletKit.pendingRequests.getAll().last;
|
||||
final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSignTypedDataV4.name);
|
||||
if (pRequest == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final address = EthUtils.getAddressFromSessionRequest(pRequest);
|
||||
|
||||
if (!_isRequestAuthorized(topic, requestAddress: address)) {
|
||||
await _rejectUnauthorizedRequest(topic, pRequest.id);
|
||||
return;
|
||||
}
|
||||
|
||||
final data = EthUtils.getDataFromSessionRequest(pRequest) as String;
|
||||
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
|
||||
|
||||
@@ -246,6 +294,7 @@ class EvmChainServiceImpl {
|
||||
method: pRequest.method,
|
||||
chainId: pRequest.chainId,
|
||||
address: address,
|
||||
topic: topic,
|
||||
transportType: pRequest.transportType.name,
|
||||
verifyContext: pRequest.verifyContext,
|
||||
);
|
||||
@@ -280,10 +329,22 @@ class EvmChainServiceImpl {
|
||||
Future<void> ethSignTransaction(String topic, dynamic parameters) async {
|
||||
debugPrint('ethSignTransaction request: $parameters');
|
||||
|
||||
final SessionRequest pRequest = walletKit.pendingRequests.getAll().last;
|
||||
final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSignTransaction.name);
|
||||
if (pRequest == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final data = EthUtils.getTransactionFromSessionRequest(pRequest);
|
||||
|
||||
if (data == null) return;
|
||||
if (data == null) {
|
||||
_respondMalformedRequest(topic, pRequest.id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_isRequestAuthorized(topic, requestAddress: data['from']?.toString())) {
|
||||
await _rejectUnauthorizedRequest(topic, pRequest.id);
|
||||
return;
|
||||
}
|
||||
|
||||
final address = EthUtils.getAddressFromSessionRequest(pRequest);
|
||||
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
|
||||
@@ -293,6 +354,7 @@ class EvmChainServiceImpl {
|
||||
method: pRequest.method,
|
||||
chainId: pRequest.chainId,
|
||||
address: address,
|
||||
topic: topic,
|
||||
transportType: pRequest.transportType.name,
|
||||
verifyContext: pRequest.verifyContext,
|
||||
);
|
||||
@@ -333,10 +395,21 @@ class EvmChainServiceImpl {
|
||||
|
||||
Future<void> ethSendTransaction(String topic, dynamic parameters) async {
|
||||
debugPrint('ethSendTransaction request: $parameters');
|
||||
final SessionRequest pRequest = walletKit.pendingRequests.getAll().last;
|
||||
final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSendTransaction.name);
|
||||
if (pRequest == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final data = EthUtils.getTransactionFromSessionRequest(pRequest);
|
||||
if (data == null) return;
|
||||
if (data == null) {
|
||||
_respondMalformedRequest(topic, pRequest.id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_isRequestAuthorized(topic, requestAddress: data['from']?.toString())) {
|
||||
await _rejectUnauthorizedRequest(topic, pRequest.id);
|
||||
return;
|
||||
}
|
||||
|
||||
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
|
||||
|
||||
@@ -344,6 +417,7 @@ class EvmChainServiceImpl {
|
||||
data,
|
||||
method: pRequest.method,
|
||||
chainId: pRequest.chainId,
|
||||
topic: topic,
|
||||
transportType: pRequest.transportType.name,
|
||||
verifyContext: pRequest.verifyContext,
|
||||
);
|
||||
@@ -379,6 +453,77 @@ class EvmChainServiceImpl {
|
||||
_handleResponseForTopic(topic, response);
|
||||
}
|
||||
|
||||
void _respondMalformedRequest(String topic, int requestId) {
|
||||
final error = Errors.getSdkError(Errors.MALFORMED_REQUEST_PARAMS);
|
||||
_handleResponseForTopic(
|
||||
topic,
|
||||
JsonRpcResponse(
|
||||
id: requestId,
|
||||
jsonrpc: "2.0",
|
||||
error: JsonRpcError(code: error.code, message: error.message),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
SessionRequest? _pendingRequest(String topic, String method) {
|
||||
final matches = walletKit.pendingRequests
|
||||
.getAll()
|
||||
.where((request) => request.topic == topic && request.method == method);
|
||||
|
||||
return matches.isEmpty ? null : matches.last;
|
||||
}
|
||||
|
||||
bool _isRequestAuthorized(String topic, {String? requestAddress}) {
|
||||
final wallet = appStore.wallet;
|
||||
if (wallet == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final keys = wcKeyService.getKeysForChain(wallet);
|
||||
if (keys.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final walletAddress = keys.first.publicKey;
|
||||
|
||||
if (!MethodsUtils.isSessionOwnedByWallet(walletKit.sessions.get(topic), walletAddress)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (requestAddress != null && !MethodsUtils.isSameAccount(requestAddress, walletAddress)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> _rejectUnauthorizedRequest(String topic, int requestId) async {
|
||||
unawaited(
|
||||
bottomSheetService.queueBottomSheet(
|
||||
isModalDismissible: true,
|
||||
widget: BottomSheetMessageDisplayWidget(
|
||||
message: S.current.wc_request_for_different_wallet,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
await walletKit.respondSessionRequest(
|
||||
topic: topic,
|
||||
response: JsonRpcResponse(
|
||||
id: requestId,
|
||||
jsonrpc: "2.0",
|
||||
error: const JsonRpcError(
|
||||
code: 4100,
|
||||
message: "The requested account has not been authorized by the user.",
|
||||
),
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
printV("rejectUnauthorizedRequest: $e");
|
||||
}
|
||||
}
|
||||
|
||||
void _handleResponseForTopic(String topic, JsonRpcResponse<dynamic> response) async {
|
||||
final session = walletKit.sessions.get(topic);
|
||||
|
||||
@@ -388,7 +533,9 @@ class EvmChainServiceImpl {
|
||||
response: response,
|
||||
);
|
||||
|
||||
if (session == null) return;
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MethodsUtils.handleRedirect(
|
||||
topic,
|
||||
@@ -397,7 +544,9 @@ class EvmChainServiceImpl {
|
||||
response.error == null,
|
||||
);
|
||||
} on ReownSignError catch (error) {
|
||||
if (session == null) return;
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MethodsUtils.handleRedirect(
|
||||
topic,
|
||||
@@ -413,6 +562,7 @@ class EvmChainServiceImpl {
|
||||
String? method,
|
||||
String? chainId,
|
||||
String? address,
|
||||
String? topic,
|
||||
VerifyContext? verifyContext,
|
||||
required String transportType,
|
||||
}) async {
|
||||
@@ -456,6 +606,7 @@ class EvmChainServiceImpl {
|
||||
method: method,
|
||||
chainId: chainId,
|
||||
address: address ?? transaction.from?.hex ?? '',
|
||||
topic: topic,
|
||||
transportType: transportType,
|
||||
verifyContext: verifyContext,
|
||||
extraModels: feeRows,
|
||||
@@ -472,13 +623,17 @@ class EvmChainServiceImpl {
|
||||
String nativeSymbol,
|
||||
) {
|
||||
final gasLimit = transaction.maxGas;
|
||||
if (gasLimit == null || gasLimit <= 0) return const [];
|
||||
if (gasLimit == null || gasLimit <= 0) {
|
||||
return const [];
|
||||
}
|
||||
|
||||
final gasLimitBig = BigInt.from(gasLimit);
|
||||
final isEip1559 = transaction.isEIP1559;
|
||||
final perGasWei =
|
||||
isEip1559 ? transaction.maxFeePerGas?.getInWei : transaction.gasPrice?.getInWei;
|
||||
if (perGasWei == null || perGasWei <= BigInt.zero) return const [];
|
||||
if (perGasWei == null || perGasWei <= BigInt.zero) {
|
||||
return const [];
|
||||
}
|
||||
|
||||
final feeWei = gasLimitBig * perGasWei;
|
||||
final feeNative = feeWei.toDouble() / 1e18;
|
||||
@@ -500,19 +655,25 @@ class EvmChainServiceImpl {
|
||||
) {
|
||||
final cryptoPart = '${_formatNativeAmount(feeNative)} $nativeSymbol';
|
||||
|
||||
if (nativeCurrency == null) return cryptoPart;
|
||||
if (nativeCurrency == null) {
|
||||
return cryptoPart;
|
||||
}
|
||||
|
||||
try {
|
||||
final fiatStore = getIt.get<FiatConversionStore>();
|
||||
final price = fiatStore.prices[nativeCurrency];
|
||||
if (price == null || price <= 0) return cryptoPart;
|
||||
if (price == null || price <= 0) {
|
||||
return cryptoPart;
|
||||
}
|
||||
|
||||
final fiatSymbol = appStore.settingsStore.fiatCurrency.title;
|
||||
final fiatValue = calculateFiatAmount(
|
||||
price: price,
|
||||
cryptoAmount: feeNative.toString(),
|
||||
);
|
||||
if (fiatValue.isEmpty || fiatValue == '0.00') return cryptoPart;
|
||||
if (fiatValue.isEmpty || fiatValue == '0.00') {
|
||||
return cryptoPart;
|
||||
}
|
||||
|
||||
return '$cryptoPart (~ $fiatValue $fiatSymbol)';
|
||||
} catch (_) {
|
||||
@@ -521,14 +682,20 @@ class EvmChainServiceImpl {
|
||||
}
|
||||
|
||||
String _formatNativeAmount(double value) {
|
||||
if (value == 0) return '0';
|
||||
if (value >= 0.0001) return value.toStringAsFixed(6);
|
||||
if (value == 0) {
|
||||
return '0';
|
||||
}
|
||||
if (value >= 0.0001) {
|
||||
return value.toStringAsFixed(6);
|
||||
}
|
||||
return value.toStringAsExponential(4);
|
||||
}
|
||||
|
||||
Future<Transaction> _ensureWCTransactionHasGasLimit(Transaction transaction) async {
|
||||
final hasGasLimit = transaction.maxGas != null && transaction.maxGas! > 0;
|
||||
if (hasGasLimit) return transaction;
|
||||
if (hasGasLimit) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
final hint = transaction.gasPrice ?? transaction.maxFeePerGas ?? await ethClient.getGasPrice();
|
||||
|
||||
@@ -689,7 +856,9 @@ $messageDetails''';
|
||||
final fieldType = field['type'] as String;
|
||||
final value = message[field['name'] as String];
|
||||
|
||||
if (value == null) continue;
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (types.containsKey(fieldType)) {
|
||||
final nestedFields = types[fieldType] as List<dynamic>;
|
||||
@@ -714,7 +883,9 @@ $messageDetails''';
|
||||
}
|
||||
|
||||
String _toCamelCase(String input) {
|
||||
if (input.isEmpty) return input;
|
||||
if (input.isEmpty) {
|
||||
return input;
|
||||
}
|
||||
return input[0].toUpperCase() + input.substring(1).toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
enum SolanaChainId { mainnet, devnet, testnet }
|
||||
enum SolanaChainId { mainnet, mainnetLegacy, devnet, testnet }
|
||||
|
||||
extension SolanaChainIdX on SolanaChainId {
|
||||
String chain() {
|
||||
@@ -6,8 +6,10 @@ extension SolanaChainIdX on SolanaChainId {
|
||||
|
||||
switch (this) {
|
||||
case SolanaChainId.mainnet:
|
||||
name = "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
|
||||
break;
|
||||
case SolanaChainId.mainnetLegacy:
|
||||
name = '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ';
|
||||
// '5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';
|
||||
break;
|
||||
case SolanaChainId.devnet:
|
||||
name = 'EtWTRABZaYq6iMfeYKouRu166VU2xqa1';
|
||||
|
||||
+86
-3
@@ -1,16 +1,20 @@
|
||||
import "dart:async";
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:blockchain_utils/base58/base58.dart';
|
||||
import 'package:blockchain_utils/blockchain_utils.dart' as blockchain_utils;
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/solana/solana_supported_methods.dart';
|
||||
import "package:cw_core/utils/print_verbose.dart";
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:on_chain/solana/solana.dart';
|
||||
import 'package:reown_walletkit/reown_walletkit.dart';
|
||||
|
||||
import "package:cake_wallet/generated/i18n.dart";
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/solana/solana_chain_id.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/utils/method_utils.dart';
|
||||
import "package:cake_wallet/src/screens/wallet_connect/widgets/bottom_sheet/bottom_sheet_message_display_widget.dart";
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
|
||||
class SolanaChainService {
|
||||
@@ -47,7 +51,16 @@ class SolanaChainService {
|
||||
Future<void> solanaSignMessage(String topic, dynamic parameters) async {
|
||||
debugPrint('solanaSignMessage request: $parameters');
|
||||
|
||||
final pRequest = walletKit.pendingRequests.getAll().last;
|
||||
final pRequest = _pendingRequest(topic, SolanaSupportedMethods.solSignMessage.name);
|
||||
if (pRequest == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_isRequestAuthorized(topic)) {
|
||||
await _rejectUnauthorizedRequest(topic, pRequest.id);
|
||||
return;
|
||||
}
|
||||
|
||||
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
|
||||
|
||||
try {
|
||||
@@ -65,6 +78,7 @@ class SolanaChainService {
|
||||
method: pRequest.method,
|
||||
chainId: pRequest.chainId,
|
||||
address: privateKey.publicKey().toAddress().address,
|
||||
topic: topic,
|
||||
transportType: pRequest.transportType.name,
|
||||
);
|
||||
|
||||
@@ -95,7 +109,16 @@ class SolanaChainService {
|
||||
Future<void> solanaSignTransaction(String topic, dynamic parameters) async {
|
||||
debugPrint('solanaSignTransaction: ${jsonEncode(parameters)}');
|
||||
|
||||
final pRequest = walletKit.pendingRequests.getAll().last;
|
||||
final pRequest = _pendingRequest(topic, SolanaSupportedMethods.solSignTransaction.name);
|
||||
if (pRequest == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_isRequestAuthorized(topic)) {
|
||||
await _rejectUnauthorizedRequest(topic, pRequest.id);
|
||||
return;
|
||||
}
|
||||
|
||||
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
|
||||
|
||||
try {
|
||||
@@ -130,6 +153,7 @@ class SolanaChainService {
|
||||
method: pRequest.method,
|
||||
chainId: pRequest.chainId,
|
||||
address: privateKey.publicKey().toAddress().address,
|
||||
topic: topic,
|
||||
transportType: pRequest.transportType.name,
|
||||
);
|
||||
|
||||
@@ -160,7 +184,16 @@ class SolanaChainService {
|
||||
Future<void> solanaSignAllTransaction(String topic, dynamic parameters) async {
|
||||
debugPrint('solanaSignAllTransaction: ${jsonEncode(parameters)}');
|
||||
|
||||
final pRequest = walletKit.pendingRequests.getAll().last;
|
||||
final pRequest = _pendingRequest(topic, SolanaSupportedMethods.solSignAllTransaction.name);
|
||||
if (pRequest == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_isRequestAuthorized(topic)) {
|
||||
await _rejectUnauthorizedRequest(topic, pRequest.id);
|
||||
return;
|
||||
}
|
||||
|
||||
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
|
||||
|
||||
try {
|
||||
@@ -174,6 +207,7 @@ class SolanaChainService {
|
||||
method: pRequest.method,
|
||||
chainId: pRequest.chainId,
|
||||
address: privateKey.publicKey().toAddress().address,
|
||||
topic: topic,
|
||||
transportType: pRequest.transportType.name,
|
||||
);
|
||||
|
||||
@@ -224,6 +258,55 @@ class SolanaChainService {
|
||||
return SolanaPrivateKey.fromSeedHex(keys[0].privateKey);
|
||||
}
|
||||
|
||||
SessionRequest? _pendingRequest(String topic, String method) {
|
||||
final matches = walletKit.pendingRequests
|
||||
.getAll()
|
||||
.where((request) => request.topic == topic && request.method == method);
|
||||
|
||||
return matches.isEmpty ? null : matches.last;
|
||||
}
|
||||
|
||||
bool _isRequestAuthorized(String topic) {
|
||||
final wallet = appStore.wallet;
|
||||
if (wallet == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final keys = wcKeyService.getKeysForChain(wallet);
|
||||
if (keys.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return MethodsUtils.isSessionOwnedByWallet(walletKit.sessions.get(topic), keys.first.publicKey);
|
||||
}
|
||||
|
||||
Future<void> _rejectUnauthorizedRequest(String topic, int requestId) async {
|
||||
unawaited(
|
||||
bottomSheetService.queueBottomSheet(
|
||||
isModalDismissible: true,
|
||||
widget: BottomSheetMessageDisplayWidget(
|
||||
message: S.current.wc_request_for_different_wallet,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
await walletKit.respondSessionRequest(
|
||||
topic: topic,
|
||||
response: JsonRpcResponse(
|
||||
id: requestId,
|
||||
jsonrpc: "2.0",
|
||||
error: const JsonRpcError(
|
||||
code: 4100,
|
||||
message: "The requested account has not been authorized by the user.",
|
||||
),
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
printV("rejectUnauthorizedRequest: $e");
|
||||
}
|
||||
}
|
||||
|
||||
void _handleResponseForTopic(String topic, JsonRpcResponse<dynamic> response) async {
|
||||
final session = walletKit.sessions.get(topic);
|
||||
|
||||
|
||||
+30
-24
@@ -43,30 +43,36 @@ class KeyServiceImpl implements WalletConnectKeyService {
|
||||
|
||||
@override
|
||||
List<ChainKeyModel> getKeys(WalletBase wallet) {
|
||||
final keys = [
|
||||
ChainKeyModel(
|
||||
chains: [
|
||||
'eip155:1',
|
||||
'eip155:5',
|
||||
'eip155:56',
|
||||
'eip155:137',
|
||||
'eip155:8453',
|
||||
'eip155:42161',
|
||||
'eip155:80001',
|
||||
],
|
||||
privateKey: _getPrivateKeyForWallet(wallet),
|
||||
publicKey: _getPublicKeyForWallet(wallet),
|
||||
),
|
||||
ChainKeyModel(
|
||||
chains: [
|
||||
'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ', // main-net
|
||||
'solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K', // test-net
|
||||
],
|
||||
privateKey: _getPrivateKeyForWallet(wallet),
|
||||
publicKey: _getPublicKeyForWallet(wallet),
|
||||
),
|
||||
];
|
||||
return keys;
|
||||
if (isEVMCompatibleChain(wallet.type)) {
|
||||
return [
|
||||
ChainKeyModel(
|
||||
chains: [
|
||||
'eip155:1',
|
||||
'eip155:56',
|
||||
'eip155:137',
|
||||
'eip155:8453',
|
||||
'eip155:42161',
|
||||
],
|
||||
privateKey: _getPrivateKeyForWallet(wallet),
|
||||
publicKey: _getPublicKeyForWallet(wallet),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
if (wallet.type == WalletType.solana) {
|
||||
return [
|
||||
ChainKeyModel(
|
||||
chains: [
|
||||
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', // main-net
|
||||
'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ', // legacy main-net id older dapps still use
|
||||
],
|
||||
privateKey: _getPrivateKeyForWallet(wallet),
|
||||
publicKey: _getPublicKeyForWallet(wallet),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -3,7 +3,6 @@ import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:eth_sig_util/util/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
@@ -42,7 +41,8 @@ abstract class WalletKitServiceBase with Store {
|
||||
) : pairings = ObservableList<PairingInfo>(),
|
||||
sessions = ObservableList<SessionData>(),
|
||||
auth = ObservableList<PendingSessionAuthRequest>(),
|
||||
isInitialized = false;
|
||||
isInitialized = false,
|
||||
isLoadingConnections = true;
|
||||
|
||||
final AppStore appStore;
|
||||
final SharedPreferences sharedPreferences;
|
||||
@@ -54,6 +54,9 @@ abstract class WalletKitServiceBase with Store {
|
||||
@observable
|
||||
bool isInitialized;
|
||||
|
||||
@observable
|
||||
bool isLoadingConnections;
|
||||
|
||||
/// The list of requests from the dapp
|
||||
@observable
|
||||
ObservableList<PairingInfo> pairings;
|
||||
@@ -91,33 +94,23 @@ abstract class WalletKitServiceBase with Store {
|
||||
_walletKit.onSessionProposal.subscribe(_onSessionProposal);
|
||||
_walletKit.onSessionProposalError.subscribe(_onSessionProposalError);
|
||||
_walletKit.onSessionConnect.subscribe(_onSessionConnect);
|
||||
_walletKit.onSessionAuthRequest.subscribe(_onSessionAuthRequest);
|
||||
|
||||
if (isEVMCompatibleChain(appStore.wallet!.type)) {
|
||||
_walletKit.onSessionAuthRequest.subscribe(_onSessionAuthRequest);
|
||||
}
|
||||
|
||||
_walletKit.pairings.onSync.subscribe(_onPairingsSync);
|
||||
_walletKit.core.pairing.onPairingDelete.subscribe(_onPairingDelete);
|
||||
_walletKit.core.pairing.onPairingExpire.subscribe(_onPairingDelete);
|
||||
|
||||
// Setup our accounts
|
||||
List<ChainKeyModel> chainKeys = walletKeyService.getKeys(appStore.wallet!);
|
||||
final chainKeys = walletKeyService.getKeys(appStore.wallet!);
|
||||
for (final chainKey in chainKeys) {
|
||||
for (final chainId in chainKey.chains) {
|
||||
if (isEVMCompatibleChain(appStore.wallet!.type)) {
|
||||
// Register account for all EVM chains (chainId is already in eip155:format)
|
||||
_walletKit.registerAccount(
|
||||
chainId: chainId,
|
||||
accountAddress: chainKey.publicKey,
|
||||
);
|
||||
} else {
|
||||
final chainNameSpace = getChainNameSpaceAndIdBasedOnWalletType(
|
||||
appStore.wallet!.type,
|
||||
);
|
||||
if (chainNameSpace == chainId) {
|
||||
_walletKit.registerAccount(
|
||||
chainId: chainId,
|
||||
accountAddress: chainKey.publicKey,
|
||||
);
|
||||
}
|
||||
}
|
||||
_walletKit.registerAccount(
|
||||
chainId: chainId,
|
||||
accountAddress: chainKey.publicKey,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,42 +137,43 @@ abstract class WalletKitServiceBase with Store {
|
||||
}
|
||||
}
|
||||
|
||||
await _emitEvent();
|
||||
|
||||
_refreshPairings();
|
||||
|
||||
sessions.clear();
|
||||
auth.clear();
|
||||
_reloadSessionsForCurrentWallet();
|
||||
|
||||
final newSessions = _walletKit.sessions.getAll();
|
||||
sessions.addAll(newSessions);
|
||||
auth.clear();
|
||||
|
||||
final newAuthRequests = _walletKit.sessionAuthRequests.getAll();
|
||||
auth.addAll(newAuthRequests);
|
||||
|
||||
if (isEVMCompatibleChain(appStore.wallet!.type)) {
|
||||
for (final cId in EVMChainId.values) {
|
||||
EvmChainServiceImpl(
|
||||
reference: cId,
|
||||
appStore: appStore,
|
||||
wcKeyService: walletKeyService,
|
||||
bottomSheetService: _bottomSheetHandler,
|
||||
walletKit: _walletKit,
|
||||
);
|
||||
}
|
||||
isLoadingConnections = false;
|
||||
for (final cId in EVMChainId.values) {
|
||||
EvmChainServiceImpl(
|
||||
reference: cId,
|
||||
appStore: appStore,
|
||||
wcKeyService: walletKeyService,
|
||||
bottomSheetService: _bottomSheetHandler,
|
||||
walletKit: _walletKit,
|
||||
);
|
||||
}
|
||||
|
||||
if (appStore.wallet!.type == WalletType.solana) {
|
||||
for (final cId in SolanaChainId.values) {
|
||||
SolanaChainService(
|
||||
reference: cId,
|
||||
appStore: appStore,
|
||||
wcKeyService: walletKeyService,
|
||||
bottomSheetService: _bottomSheetHandler,
|
||||
walletKit: _walletKit,
|
||||
);
|
||||
}
|
||||
for (final cId in SolanaChainId.values) {
|
||||
SolanaChainService(
|
||||
reference: cId,
|
||||
appStore: appStore,
|
||||
wcKeyService: walletKeyService,
|
||||
bottomSheetService: _bottomSheetHandler,
|
||||
walletKit: _walletKit,
|
||||
);
|
||||
}
|
||||
|
||||
unawaited(() async {
|
||||
try {
|
||||
await _emitEvent();
|
||||
} catch (e) {
|
||||
printV("emitEvent failed: $e");
|
||||
}
|
||||
}());
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -195,6 +189,10 @@ abstract class WalletKitServiceBase with Store {
|
||||
for (var session in engineSessions) {
|
||||
final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
|
||||
for (var chain in chainKeys) {
|
||||
if (!MethodsUtils.isSessionOwnedByWallet(session, chain.publicKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var chainID in chain.chains) {
|
||||
try {
|
||||
final events = NamespaceUtils.getNamespacesEventsForChain(
|
||||
@@ -228,8 +226,21 @@ abstract class WalletKitServiceBase with Store {
|
||||
}
|
||||
|
||||
@action
|
||||
FutureOr<void> onDispose() {
|
||||
log('walletKit dispose');
|
||||
void resetConnectionsState() {
|
||||
sessions.clear();
|
||||
auth.clear();
|
||||
pairings.clear();
|
||||
|
||||
isInitialized = false;
|
||||
isLoadingConnections = true;
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> onDispose() async {
|
||||
log("walletKit dispose");
|
||||
|
||||
resetConnectionsState();
|
||||
|
||||
_walletKit.core.removeLogListener(_logListener);
|
||||
|
||||
_walletKit.core.pairing.onPairingInvalid.unsubscribe(_onPairingInvalid);
|
||||
@@ -246,11 +257,11 @@ abstract class WalletKitServiceBase with Store {
|
||||
_walletKit.core.pairing.onPairingDelete.unsubscribe(_onPairingDelete);
|
||||
_walletKit.core.pairing.onPairingExpire.unsubscribe(_onPairingDelete);
|
||||
|
||||
sessions.clear();
|
||||
auth.clear();
|
||||
pairings.clear();
|
||||
|
||||
isInitialized = false;
|
||||
try {
|
||||
await _walletKit.core.relayClient.disconnect().timeout(const Duration(seconds: 3));
|
||||
} catch (e) {
|
||||
printV("walletKit relay disconnect: $e");
|
||||
}
|
||||
}
|
||||
|
||||
ReownWalletKit get walletKit => _walletKit;
|
||||
@@ -534,8 +545,7 @@ abstract class WalletKitServiceBase with Store {
|
||||
}
|
||||
|
||||
await _removePairingTopicFromLocalStorage(topic);
|
||||
sessions.clear();
|
||||
sessions.addAll(_walletKit.sessions.getAll());
|
||||
_reloadSessionsForCurrentWallet();
|
||||
_refreshPairings();
|
||||
}
|
||||
|
||||
@@ -559,8 +569,7 @@ abstract class WalletKitServiceBase with Store {
|
||||
printV('disconnectSession: $e');
|
||||
}
|
||||
|
||||
sessions.clear();
|
||||
sessions.addAll(_walletKit.sessions.getAll());
|
||||
_reloadSessionsForCurrentWallet();
|
||||
|
||||
if (pairingTopic != null &&
|
||||
!_walletKit.sessions.getAll().any((s) => s.pairingTopic == pairingTopic)) {
|
||||
@@ -619,6 +628,24 @@ abstract class WalletKitServiceBase with Store {
|
||||
pairings.addAll(filteredPairings);
|
||||
}
|
||||
|
||||
@action
|
||||
void _reloadSessionsForCurrentWallet() {
|
||||
sessions.clear();
|
||||
|
||||
final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
|
||||
if (chainKeys.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final walletPublicKey = chainKeys.first.publicKey;
|
||||
|
||||
sessions.addAll(
|
||||
_walletKit.sessions
|
||||
.getAll()
|
||||
.where((session) => MethodsUtils.isSessionOwnedByWallet(session, walletPublicKey)),
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
List<SessionData> getSessionsForPairingInfo(PairingInfo pairing) {
|
||||
return sessions.where((element) => element.pairingTopic == pairing.topic).toList();
|
||||
|
||||
@@ -11,9 +11,27 @@ import 'package:flutter/material.dart';
|
||||
import 'package:reown_walletkit/reown_walletkit.dart';
|
||||
|
||||
class MethodsUtils {
|
||||
static final walletKit = getIt.get<WalletKitService>().walletKit;
|
||||
static ReownWalletKit get walletKit => getIt.get<WalletKitService>().walletKit;
|
||||
static final bottomSheetService = getIt.get<BottomSheetService>();
|
||||
|
||||
static bool isSessionOwnedByWallet(SessionData? session, String walletPublicKey) {
|
||||
if (session == null || walletPublicKey.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final accounts = session.namespaces.values.expand((namespace) => namespace.accounts);
|
||||
|
||||
return accounts.any((account) => isSameAccount(account.split(":").last, walletPublicKey));
|
||||
}
|
||||
|
||||
static bool isSameAccount(String a, String b) {
|
||||
if (a.startsWith("0x") && b.startsWith("0x")) {
|
||||
return a.toLowerCase() == b.toLowerCase();
|
||||
}
|
||||
|
||||
return a == b;
|
||||
}
|
||||
|
||||
static const _transactionMethods = {
|
||||
'eth_sendTransaction',
|
||||
'eth_signTransaction',
|
||||
@@ -28,13 +46,19 @@ class MethodsUtils {
|
||||
String? method,
|
||||
String? chainId,
|
||||
String? address,
|
||||
String? topic,
|
||||
required String transportType,
|
||||
List<WCConnectionModel> extraModels = const [],
|
||||
VerifyContext? verifyContext,
|
||||
}) async {
|
||||
final appStore = getIt.get<AppStore>();
|
||||
final pending = walletKit.pendingRequests.getAll();
|
||||
final session = pending.isNotEmpty ? walletKit.sessions.get(pending.last.topic) : null;
|
||||
SessionData? session;
|
||||
if (topic != null) {
|
||||
session = walletKit.sessions.get(topic);
|
||||
} else {
|
||||
final pending = walletKit.pendingRequests.getAll();
|
||||
session = pending.isNotEmpty ? walletKit.sessions.get(pending.last.topic) : null;
|
||||
}
|
||||
final dAppMetadata = session?.peer.metadata;
|
||||
|
||||
final isTransaction = method != null && _transactionMethods.contains(method);
|
||||
|
||||
@@ -12,6 +12,7 @@ import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/permission_handler.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import "package:flutter/cupertino.dart";
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
@@ -145,6 +146,26 @@ class WalletConnectConnectionsView extends StatelessWidget {
|
||||
const SizedBox(height: 24),
|
||||
Observer(
|
||||
builder: (_) {
|
||||
if (walletKitService.isLoadingConnections) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 32),
|
||||
child: Center(
|
||||
child: Column(
|
||||
spacing: 12,
|
||||
children: [
|
||||
const CupertinoActivityIndicator(),
|
||||
Text(
|
||||
"${S.of(context).loading}...",
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: colors.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (walletKitService.pairings.isEmpty) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 32),
|
||||
|
||||
@@ -20,7 +20,9 @@ class NewSimpleCheckbox extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: value
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
: Theme.of(context).brightness == Brightness.light
|
||||
? Theme.of(context).colorScheme.onSurfaceVariant.withAlpha(80)
|
||||
: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(50)),
|
||||
),
|
||||
height: 24,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import "dart:async";
|
||||
|
||||
import "package:cake_wallet/core/amount_parsing_proxy.dart";
|
||||
import "package:cake_wallet/di.dart";
|
||||
import "package:cake_wallet/entities/preferences_key.dart";
|
||||
@@ -60,13 +58,17 @@ abstract class AppStoreBase with Store {
|
||||
Future<void> changeCurrentWallet(
|
||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet) async {
|
||||
final changingToSameWalletType = this.wallet?.type == wallet.type;
|
||||
final previousWalletType = this.wallet?.type;
|
||||
|
||||
await this.wallet?.close(shouldCleanup: !changingToSameWalletType);
|
||||
this.wallet = wallet;
|
||||
this.wallet!.setExceptionHandler(ExceptionHandler.onError);
|
||||
|
||||
if (isWalletConnectCompatibleChain(wallet.type)) {
|
||||
unawaited(_setupWalletConnect());
|
||||
getIt.get<WalletKitService>().resetConnectionsState();
|
||||
_queueWalletConnectAction(_setupWalletConnect);
|
||||
} else if (previousWalletType != null && isWalletConnectCompatibleChain(previousWalletType)) {
|
||||
_queueWalletConnectAction(_disposeWalletConnect);
|
||||
}
|
||||
await getIt.get<SharedPreferences>().setString(PreferencesKey.currentWalletName, wallet.name);
|
||||
await getIt
|
||||
@@ -74,6 +76,12 @@ abstract class AppStoreBase with Store {
|
||||
.setInt(PreferencesKey.currentWalletType, serializeToInt(wallet.type));
|
||||
}
|
||||
|
||||
Future<void> _lastWalletConnectAction = Future.value();
|
||||
|
||||
void _queueWalletConnectAction(Future<void> Function() action) {
|
||||
_lastWalletConnectAction = _lastWalletConnectAction.then((_) => action());
|
||||
}
|
||||
|
||||
Future<void> _setupWalletConnect() async {
|
||||
try {
|
||||
final wcService = getIt.get<WalletKitService>();
|
||||
@@ -84,4 +92,12 @@ abstract class AppStoreBase with Store {
|
||||
printV("WalletConnect setup failed: $e\n$s");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _disposeWalletConnect() async {
|
||||
try {
|
||||
await getIt.get<WalletKitService>().onDispose();
|
||||
} catch (e) {
|
||||
printV("WalletConnect teardown failed: $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'dart:io';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/utilities.dart';
|
||||
import 'package:cake_wallet/decred/decred.dart';
|
||||
import 'package:cake_wallet/dogecoin/dogecoin.dart';
|
||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||
import 'package:cake_wallet/core/secure_storage.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
@@ -168,6 +169,7 @@ abstract class SettingsStoreBase with Store {
|
||||
TransactionPriority? initialZanoTransactionPriority,
|
||||
TransactionPriority? initialDecredTransactionPriority,
|
||||
TransactionPriority? initialZcashTransactionPriority,
|
||||
TransactionPriority? initialDogecoinTransactionPriority,
|
||||
Country? initialCakePayCountry})
|
||||
: nodes = ObservableMap<WalletType, Node>.of(nodes),
|
||||
powNodes = ObservableMap<WalletType, Node>.of(powNodes),
|
||||
@@ -273,6 +275,9 @@ abstract class SettingsStoreBase with Store {
|
||||
if (initialZcashTransactionPriority != null) {
|
||||
priority[WalletType.zcash] = initialZcashTransactionPriority;
|
||||
}
|
||||
if (initialDogecoinTransactionPriority != null) {
|
||||
priority[WalletType.dogecoin] = initialDogecoinTransactionPriority;
|
||||
}
|
||||
|
||||
if (initialCakePayCountry != null) {
|
||||
selectedCakePayCountry = initialCakePayCountry;
|
||||
@@ -345,6 +350,9 @@ abstract class SettingsStoreBase with Store {
|
||||
case WalletType.zcash:
|
||||
key = PreferencesKey.zcashTransactionPriority;
|
||||
break;
|
||||
case WalletType.dogecoin:
|
||||
key = PreferencesKey.dogecoinTransactionPriority;
|
||||
break;
|
||||
default:
|
||||
key = null;
|
||||
}
|
||||
@@ -1194,6 +1202,7 @@ abstract class SettingsStoreBase with Store {
|
||||
TransactionPriority? zanoTransactionPriority;
|
||||
TransactionPriority? decredTransactionPriority;
|
||||
TransactionPriority? zcashTransactionPriority;
|
||||
TransactionPriority? dogecoinTransactionPriority;
|
||||
|
||||
if (sharedPreferences.getInt(PreferencesKey.havenTransactionPriority) != null) {
|
||||
havenTransactionPriority = monero?.deserializeMoneroTransactionPriority(
|
||||
@@ -1241,6 +1250,10 @@ abstract class SettingsStoreBase with Store {
|
||||
zcashTransactionPriority = zcash?.deserializeZcashTransactionPriority(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.zcashTransactionPriority)!);
|
||||
}
|
||||
if (sharedPreferences.getInt(PreferencesKey.dogecoinTransactionPriority) != null) {
|
||||
dogecoinTransactionPriority = dogecoin?.deserializeDogeCoinTransactionPriority(
|
||||
sharedPreferences.getInt(PreferencesKey.dogecoinTransactionPriority)!);
|
||||
}
|
||||
|
||||
moneroTransactionPriority ??= monero?.getDefaultTransactionPriority();
|
||||
bitcoinTransactionPriority ??= bitcoin?.getMediumTransactionPriority();
|
||||
@@ -1256,6 +1269,7 @@ abstract class SettingsStoreBase with Store {
|
||||
bscTransactionPriority ??= evm?.getDefaultTransactionPriority();
|
||||
zanoTransactionPriority ??= zano?.getDefaultTransactionPriority();
|
||||
zcashTransactionPriority ??= zcash?.getDefaultTransactionPriority();
|
||||
dogecoinTransactionPriority ??= dogecoin?.getDefaultTransactionPriority();
|
||||
|
||||
final currentBalanceDisplayMode = BalanceDisplayMode.deserialize(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
|
||||
@@ -1744,6 +1758,7 @@ abstract class SettingsStoreBase with Store {
|
||||
initialBitcoinCashTransactionPriority: bitcoinCashTransactionPriority,
|
||||
initialDecredTransactionPriority: decredTransactionPriority,
|
||||
initialZcashTransactionPriority: zcashTransactionPriority,
|
||||
initialDogecoinTransactionPriority: dogecoinTransactionPriority,
|
||||
initialShouldRequireTOTP2FAForAccessingWallet: shouldRequireTOTP2FAForAccessingWallet,
|
||||
initialShouldRequireTOTP2FAForSendsToContact: shouldRequireTOTP2FAForSendsToContact,
|
||||
initialShouldRequireTOTP2FAForSendsToNonContact: shouldRequireTOTP2FAForSendsToNonContact,
|
||||
@@ -1777,12 +1792,16 @@ abstract class SettingsStoreBase with Store {
|
||||
Future<void> reload() async {
|
||||
final sharedPreferences = await getIt.getAsync<SharedPreferences>();
|
||||
|
||||
fiatCurrency = FiatCurrency.deserialize(
|
||||
raw: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!);
|
||||
final savedFiatCurrency = sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey);
|
||||
if (savedFiatCurrency != null) {
|
||||
fiatCurrency = FiatCurrency.deserialize(raw: savedFiatCurrency);
|
||||
}
|
||||
|
||||
priority[WalletType.monero] = monero?.deserializeMoneroTransactionPriority(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!) ??
|
||||
priority[WalletType.monero]!;
|
||||
if (monero != null &&
|
||||
sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority) != null) {
|
||||
priority[WalletType.monero] = monero!.deserializeMoneroTransactionPriority(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!);
|
||||
}
|
||||
|
||||
if (wownero != null &&
|
||||
sharedPreferences.getInt(PreferencesKey.wowneroTransactionPriority) != null) {
|
||||
@@ -1843,6 +1862,11 @@ abstract class SettingsStoreBase with Store {
|
||||
priority[WalletType.zcash] = zcash!.deserializeZcashTransactionPriority(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.zcashTransactionPriority)!);
|
||||
}
|
||||
if (dogecoin != null &&
|
||||
sharedPreferences.getInt(PreferencesKey.dogecoinTransactionPriority) != null) {
|
||||
priority[WalletType.dogecoin] = dogecoin!.deserializeDogeCoinTransactionPriority(
|
||||
sharedPreferences.getInt(PreferencesKey.dogecoinTransactionPriority)!);
|
||||
}
|
||||
|
||||
final generateSubaddresses =
|
||||
sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey);
|
||||
|
||||
@@ -59,6 +59,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
||||
case WalletType.solana:
|
||||
case WalletType.tron:
|
||||
case WalletType.zcash:
|
||||
case WalletType.decred:
|
||||
return true;
|
||||
|
||||
case WalletType.bitcoin:
|
||||
@@ -74,7 +75,6 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
||||
case WalletType.none:
|
||||
case WalletType.haven:
|
||||
case WalletType.zano:
|
||||
case WalletType.decred:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,8 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
||||
WalletType.zano,
|
||||
WalletType.dogecoin,
|
||||
WalletType.zcash,
|
||||
].contains(type);
|
||||
WalletType.decred,
|
||||
].contains(type);
|
||||
|
||||
@computed
|
||||
bool get addCustomNode => _addCustomNode;
|
||||
|
||||
@@ -96,7 +96,6 @@ abstract class DashboardViewModelBase with Store {
|
||||
isShowFirstYatIntroduction = false,
|
||||
isShowSecondYatIntroduction = false,
|
||||
isShowThirdYatIntroduction = false,
|
||||
isMigratingToIronwood = false,
|
||||
filterItems = [],
|
||||
exchangeFilterItems = [],
|
||||
subname = '',
|
||||
@@ -251,8 +250,6 @@ abstract class DashboardViewModelBase with Store {
|
||||
|
||||
reaction((_) => tradesStore.trades, (_) => tradeMonitor.monitorActiveTrades(wallet.id));
|
||||
|
||||
addZcashMigrationReaction();
|
||||
|
||||
tradeMonitor.monitorActiveTrades(wallet.id);
|
||||
}
|
||||
|
||||
@@ -377,21 +374,9 @@ abstract class DashboardViewModelBase with Store {
|
||||
);
|
||||
}
|
||||
|
||||
@observable
|
||||
ReactionDisposer? zcashMigrationReactionDisposer;
|
||||
|
||||
@action
|
||||
void addZcashMigrationReaction() {
|
||||
zcashMigrationReactionDisposer?.reaction.dispose();
|
||||
zcashMigrationReactionDisposer = null;
|
||||
|
||||
if (wallet.type == WalletType.zcash) {
|
||||
zcashMigrationReactionDisposer = reaction((_) => wallet.balance.values.first, (_) async {
|
||||
isMigratingToIronwood =
|
||||
wallet.type == WalletType.zcash && await zcash!.hasOrchardMigratableBalance(wallet);
|
||||
});
|
||||
}
|
||||
}
|
||||
@computed
|
||||
bool get isMigratingToIronwood =>
|
||||
wallet.type == WalletType.zcash && (zcash?.hasOrchardMigratableBalance(wallet) ?? false);
|
||||
|
||||
@computed
|
||||
bool get isSyncHeavy {
|
||||
@@ -635,7 +620,7 @@ abstract class DashboardViewModelBase with Store {
|
||||
|
||||
if (settingsStore.mwebAdDismissed) return false;
|
||||
|
||||
return Platform.isAndroid || Platform.isIOS;
|
||||
return (Platform.isAndroid || Platform.isIOS) && !wallet.isHardwareWallet;
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -1289,8 +1274,6 @@ abstract class DashboardViewModelBase with Store {
|
||||
name = wallet.name;
|
||||
loadFilterItems();
|
||||
|
||||
addZcashMigrationReaction();
|
||||
|
||||
if (wallet.type == WalletType.monero) {
|
||||
subname = monero!.getCurrentAccount(wallet).label;
|
||||
|
||||
@@ -1572,9 +1555,6 @@ abstract class DashboardViewModelBase with Store {
|
||||
}
|
||||
}
|
||||
|
||||
@observable
|
||||
bool isMigratingToIronwood;
|
||||
|
||||
String getTransactionType(TransactionInfo tx) {
|
||||
if (wallet.type == WalletType.bitcoin) {
|
||||
if (tx.isReplaced == true) return ' (replaced)';
|
||||
|
||||
@@ -35,7 +35,8 @@ abstract class ReceiveOptionViewModelBase with Store {
|
||||
ReceivePageOption selectedReceiveOption;
|
||||
|
||||
@computed
|
||||
List<ReceivePageOption> get options => _wallet.walletAddresses.receivePageOptions;
|
||||
List<ReceivePageOption> get options =>
|
||||
_wallet.walletAddresses.receivePageOptions.where(_wallet.receiveOptionAvailable).toList();
|
||||
|
||||
String get walletTypeString => walletTypeToString(_wallet.type);
|
||||
|
||||
|
||||
@@ -167,9 +167,10 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
|
||||
bool get isEVMWallet => isEVMCompatibleChain(walletType);
|
||||
|
||||
@action
|
||||
CryptoCurrency _outputCryptoCurrencyHandler([CryptoCurrency? override]) {
|
||||
if (override != null && override != selectedCryptoCurrency) selectedCryptoCurrency = override;
|
||||
if (override != null && override != selectedCryptoCurrency) {
|
||||
runInAction(() => selectedCryptoCurrency = override);
|
||||
}
|
||||
|
||||
return selectedCryptoCurrency;
|
||||
}
|
||||
@@ -335,6 +336,18 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
@observable
|
||||
PendingTransaction? pendingTransaction;
|
||||
|
||||
String? get pendingTransactionAdditionalCostNotice {
|
||||
final additionalCost = pendingTransaction?.additionalCost;
|
||||
|
||||
if (additionalCost == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return S.current.recipient_account_creation_fee(
|
||||
_appStore.amountParsingProxy.asDisplayStringWithSymbol(additionalCost),
|
||||
);
|
||||
}
|
||||
|
||||
@computed
|
||||
String get balance {
|
||||
if (walletType == WalletType.litecoin && coinTypeToSpendFrom == UnspentCoinType.mweb) {
|
||||
@@ -1177,11 +1190,11 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
await sharedPreferences.setString(PreferencesKey.backgroundSyncLastTrigger(wallet.name),
|
||||
DateTime.now().add(Duration(minutes: 1)).toIso8601String());
|
||||
} catch (e) {
|
||||
if (e is JupiterSwapFailedException) {
|
||||
await _updateSolanaTrade(signature: e.signature, isSuccess: false);
|
||||
}
|
||||
state = FailureState(translateErrorMessage(e, wallet.type, wallet.currency));
|
||||
await _updateSolanaTrade(signature: '', isSuccess: false);
|
||||
|
||||
final failedSignature = e is JupiterSwapFailedException ? e.signature : "";
|
||||
|
||||
await _updateSolanaTrade(signature: failedSignature, isSuccess: false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1507,6 +1520,10 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
return S.current.solana_no_associated_token_account_exception;
|
||||
}
|
||||
|
||||
if (error is AmbiguousTokenSymbolException) {
|
||||
return S.current.ambiguous_token_symbol_exception(error.symbol);
|
||||
}
|
||||
|
||||
if (errorMessage.contains('found no record of a prior credit')) {
|
||||
return S.current.insufficient_funds_for_tx;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ abstract class OtherSettingsViewModelBase with Store {
|
||||
final SettingsStore _settingsStore;
|
||||
final SendViewModel sendViewModel;
|
||||
|
||||
bool get hasSignVerify => _wallet.canSignMessages;
|
||||
|
||||
@computed
|
||||
TransactionPriority get transactionPriority {
|
||||
final priority = _settingsStore.getPriority(walletType, chainId: chainId);
|
||||
@@ -173,6 +175,10 @@ abstract class OtherSettingsViewModelBase with Store {
|
||||
return null;
|
||||
}
|
||||
|
||||
bool get hasPayjoin => _wallet.hasPayjoinSupport;
|
||||
|
||||
bool get hasLightning => _wallet.hasLightningSupport;
|
||||
|
||||
Future<File?> getLightningLog() async {
|
||||
final path = await pathForWalletDir(name: _wallet.name, type: walletType);
|
||||
final logFile = File("$path/lightning.log");
|
||||
|
||||
@@ -25,7 +25,12 @@ abstract class PrivacySettingsViewModelBase with Store {
|
||||
bool get isBitcoin => _wallet.type == WalletType.bitcoin;
|
||||
|
||||
@computed
|
||||
bool get hasMWEB => _wallet.type == WalletType.litecoin && (Platform.isIOS || Platform.isAndroid);
|
||||
bool get hasSilentPaymentsScanning => _wallet.hasSilentPaymentsScanning;
|
||||
|
||||
@computed
|
||||
bool get hasMWEB =>
|
||||
_wallet.type == WalletType.litecoin && (Platform.isIOS || Platform.isAndroid) &&
|
||||
!_wallet.isHardwareWallet;
|
||||
|
||||
@computed
|
||||
bool get isAutoGenerateSubaddressesEnabled =>
|
||||
@@ -108,11 +113,10 @@ abstract class PrivacySettingsViewModelBase with Store {
|
||||
bool get usePayjoin => _settingsStore.usePayjoin;
|
||||
|
||||
@computed
|
||||
bool get canUsePayjoin => _wallet.type == WalletType.bitcoin && DeviceInfo.instance.isMobile;
|
||||
bool get canUsePayjoin => _wallet.hasPayjoinSupport && DeviceInfo.instance.isMobile;
|
||||
|
||||
@computed
|
||||
bool get canUseLightning =>
|
||||
_wallet.type == WalletType.bitcoin && !Platform.isWindows && !Platform.isLinux;
|
||||
bool get canUseLightning => _wallet.hasLightningSupport;
|
||||
|
||||
@computed
|
||||
bool get useLightning => _wallet.type == WalletType.bitcoin && bitcoin!.useLightning(_wallet);
|
||||
|
||||
@@ -179,6 +179,8 @@ abstract class WalletCreationVMBase with Store {
|
||||
);
|
||||
}
|
||||
return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
|
||||
case WalletType.decred:
|
||||
return DerivationInfo(derivationType: DerivationType.bip39);
|
||||
default:
|
||||
return DerivationInfo(derivationType: DerivationType.unknown);
|
||||
}
|
||||
|
||||
@@ -131,6 +131,10 @@ abstract class WalletGroupsDisplayViewModelBase with Store {
|
||||
bool isNotMoneroBip39Wallet =
|
||||
wallet.type == WalletType.monero && di.derivationType != DerivationType.bip39;
|
||||
|
||||
bool isNotDecredBip39Wallet = wallet.type == WalletType.decred &&
|
||||
di.derivationType != DerivationType.bip39 &&
|
||||
di.derivationType != DerivationType.unknown;
|
||||
|
||||
// Exclude if any of these conditions are true
|
||||
shouldExcludeGroup = shouldExcludeGroup ||
|
||||
isNonBIP39Wallet ||
|
||||
@@ -138,7 +142,8 @@ abstract class WalletGroupsDisplayViewModelBase with Store {
|
||||
isElectrumDerivationType ||
|
||||
isSameTypeAsSelectedWallet ||
|
||||
isNonSeedWallet ||
|
||||
isNotMoneroBip39Wallet;
|
||||
isNotMoneroBip39Wallet ||
|
||||
isNotDecredBip39Wallet;
|
||||
}
|
||||
|
||||
if (shouldExcludeGroup) continue;
|
||||
|
||||
@@ -149,7 +149,11 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
|
||||
network: zcashNetwork,
|
||||
);
|
||||
case WalletType.decred:
|
||||
return decred!.createDecredNewWalletCredentials(name: name);
|
||||
return decred!.createDecredNewWalletCredentials(
|
||||
name: name,
|
||||
password: walletPassword,
|
||||
passphrase: passphrase,
|
||||
mnemonic: newWalletArguments!.mnemonic);
|
||||
case WalletType.none:
|
||||
case WalletType.haven:
|
||||
throw Exception('Unexpected type: ${type.toString()}');
|
||||
|
||||
@@ -216,6 +216,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||
name: name,
|
||||
mnemonic: seed,
|
||||
password: password,
|
||||
passphrase: passphrase,
|
||||
);
|
||||
case WalletType.zcash:
|
||||
return zcash!.createZcashRestoreWalletFromSeedCredentials(
|
||||
|
||||
@@ -223,7 +223,7 @@ class CWZcash extends Zcash {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> hasOrchardMigratableBalance(WalletBase wallet) {
|
||||
bool hasOrchardMigratableBalance(WalletBase wallet) {
|
||||
return (wallet as ZcashWallet).hasOrchardMigratableBalance();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user