From 73588071ba5065a2df37a4d1bf5a041e4e071048 Mon Sep 17 00:00:00 2001 From: cyan Date: Fri, 27 Jun 2025 14:05:54 +0200 Subject: [PATCH 1/5] feat(tor): add Tor endpoints for fiat-api and service-api (#2339) --- lib/core/fiat_conversion_service.dart | 3 +-- .../dashboard/dashboard_view_model.dart | 17 +++++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/core/fiat_conversion_service.dart b/lib/core/fiat_conversion_service.dart index 046c2b149..4a33feb63 100644 --- a/lib/core/fiat_conversion_service.dart +++ b/lib/core/fiat_conversion_service.dart @@ -5,8 +5,7 @@ import 'dart:convert'; import 'package:cake_wallet/.secrets.g.dart' as secrets; const _fiatApiClearNetAuthority = 'fiat-api.cakewallet.com'; -// const _fiatApiOnionAuthority = 'n4z7bdcmwk2oyddxvzaap3x2peqcplh3pzdy7tpkk5ejz5n4mhfvoxqd.onion'; -const _fiatApiOnionAuthority = _fiatApiClearNetAuthority; +const _fiatApiOnionAuthority = 'kfkyguqtz5vcnbvar5pjgddkaeawbo4j3r4fj3e22k3tzqageplosiid.onion'; const _fiatApiPath = '/v2/rates'; Future _fetchPrice(String crypto, String fiat, bool torOnly) async { diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart index db359a3f5..eab0c8572 100644 --- a/lib/view_model/dashboard/dashboard_view_model.dart +++ b/lib/view_model/dashboard/dashboard_view_model.dart @@ -1123,13 +1123,18 @@ abstract class DashboardViewModelBase with Store { Future _getServicesStatus() async { try { if (isEnabledBulletinAction) { - final uri = Uri.https( - "service-api.cakewallet.com", - "/v1/active-notices", - {'key': secrets.fiatApiKey}, + final res = await ProxyWrapper().get( + clearnetUri: Uri.https( + "service-api.cakewallet.com", + "/v1/active-notices", + {'key': secrets.fiatApiKey}, + ), + onionUri: Uri.http( + "jpirgl4lrwzjgdqj2nsv3g7twhp2efzty5d3cnypktyczzqfc5qcwwyd.onion", + "/v1/active-notices", + {'key': secrets.fiatApiKey}, + ), ); - - final res = await ProxyWrapper().get(clearnetUri: uri); if (res.statusCode < 200 || res.statusCode >= 300) { throw res.body; } From 900304d40532e9226439a38387853519299f670a Mon Sep 17 00:00:00 2001 From: cyan Date: Fri, 27 Jun 2025 14:06:56 +0200 Subject: [PATCH 2/5] fix(cw_monero): keys nullcheck handling (#2338) add default values to monero wallet keys functions in order to prevent null check crashes --- cw_monero/lib/api/wallet.dart | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/cw_monero/lib/api/wallet.dart b/cw_monero/lib/api/wallet.dart index e98ba71ca..148b271ff 100644 --- a/cw_monero/lib/api/wallet.dart +++ b/cw_monero/lib/api/wallet.dart @@ -116,12 +116,17 @@ String getSeedLegacy(String? language) { } String getPassphrase() { - return currentWallet!.getCacheAttribute(key: "cakewallet.passphrase"); + return currentWallet?.getCacheAttribute(key: "cakewallet.passphrase") ?? ""; } Map>> addressCache = {}; String getAddress({int accountIndex = 0, int addressIndex = 0}) { + // this is a workaround for when we switch the wallet pointer, + // it should never reach UI but should be good enough to prevent gray screen + // or other errors because of forced null check. + if (currentWallet == null) return ""; + // printV("getaddress: ${accountIndex}/${addressIndex}: ${monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)}: ${monero.Wallet_address(wptr!, accountIndex: accountIndex, addressIndex: addressIndex)}"); // this could be a while loop, but I'm in favor of making it if to not cause freezes if (currentWallet!.numSubaddresses(accountIndex: accountIndex)-1 < addressIndex) { @@ -272,13 +277,13 @@ void closeCurrentWallet() { currentWallet!.stop(); } -String getSecretViewKey() => currentWallet!.secretViewKey(); +String getSecretViewKey() => currentWallet?.secretViewKey() ?? ""; -String getPublicViewKey() => currentWallet!.publicViewKey(); +String getPublicViewKey() => currentWallet?.publicViewKey() ?? ""; -String getSecretSpendKey() => currentWallet!.secretSpendKey(); +String getSecretSpendKey() => currentWallet?.secretSpendKey() ?? ""; -String getPublicSpendKey() => currentWallet!.publicSpendKey(); +String getPublicSpendKey() => currentWallet?.publicSpendKey() ?? ""; class SyncListener { SyncListener(this.onNewBlock, this.onNewTransaction) From d0827dd39e660bc30152f67d3bfbf41450ed4ba6 Mon Sep 17 00:00:00 2001 From: Serhii Date: Fri, 27 Jun 2025 15:47:34 +0300 Subject: [PATCH 3/5] add USDT Binance Smart Chain (BSC) support (#2341) --- assets/images/usdtbsc_icon.png | Bin 0 -> 920 bytes cw_core/lib/crypto_currency.dart | 4 +++- .../provider/thorchain_exchange.provider.dart | 3 ++- .../provider/trocador_exchange_provider.dart | 2 ++ 4 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 assets/images/usdtbsc_icon.png diff --git a/assets/images/usdtbsc_icon.png b/assets/images/usdtbsc_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9f2cda2370168aaad92eeec449730458b6df7d2a GIT binary patch literal 920 zcmV;J184k+P)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H110_jB zK~y-6t(0GEQ*{)_Kc~Gb_omsDvMSwN0wl_iWjstLi((TJd72L<4Iv>IU?yZ~OAI7N z5oLx!B$>l`sV_t&nTaOyWSm6tWuYO9*xwP8<7#q-7?A8PwMwMYWX*n_pV0Tj%vUdzzXu&4GZ|^&i-})wwl4|KPV& z%Kuj`S6fxG>LxOo;~rGstMotR^DWGEbxp;0?8xREM}C@|6gT$s^tAq6C`flpOYVMG z*L1yQ&99n7+(7j#BA){S@U&@WuFcHce}818>1H~;*))vYrnHVNoz?Bj zTFKQheW-kCEcOi|`+*`rAr#{Dph><2SNj&3ob@m{>)~qOBKZ=W9yC#v(KTDHx;c^9 zhw7m3j|orh_dj^tM~Q@&TfRJOaO#qUDhS&7Sl|lu4ZzuO>dbD06AxLN-gNrzNB;>} uX~E#ePQ`mnL|+C_mEQ%Ye{ODe2;d)xgHl-NOT0?}0000 with Serializable implemen CryptoCurrency.zano, CryptoCurrency.ton, CryptoCurrency.flip, - CryptoCurrency.deuro + CryptoCurrency.deuro, + CryptoCurrency.usdtbsc, ]; static const havenCurrencies = [ @@ -233,6 +234,7 @@ class CryptoCurrency extends EnumerableItem with Serializable implemen static const zano = CryptoCurrency(title: 'ZANO', tag: 'ZANO', fullName: 'Zano', raw: 96, name: 'zano', iconPath: 'assets/images/zano_icon.png', decimals: 12); static const flip = CryptoCurrency(title: 'FLIP', tag: 'ETH', fullName: 'Chainflip', raw: 97, name: 'flip', iconPath: 'assets/images/flip_icon.png', decimals: 18); static const deuro = CryptoCurrency(title: 'DEURO', tag: 'ETH', fullName: 'Decentralized Euro', raw: 98, name: 'deuro', iconPath: 'assets/images/deuro_icon.png', decimals: 18); + static const usdtbsc = CryptoCurrency(title: 'USDT', tag: 'BSC', fullName: 'USDT Binance coin', raw: 99, name: 'usdtbsc', iconPath: 'assets/images/usdtbsc_icon.png', decimals: 18); static final Map _rawCurrencyMap = [...all, ...havenCurrencies].fold>({}, (acc, item) { diff --git a/lib/exchange/provider/thorchain_exchange.provider.dart b/lib/exchange/provider/thorchain_exchange.provider.dart index 0cdb2a423..16246abac 100644 --- a/lib/exchange/provider/thorchain_exchange.provider.dart +++ b/lib/exchange/provider/thorchain_exchange.provider.dart @@ -23,6 +23,7 @@ class ThorChainExchangeProvider extends ExchangeProvider { // CryptoCurrency.eth, CryptoCurrency.ltc, CryptoCurrency.bch, + CryptoCurrency.usdtbsc, // CryptoCurrency.aave, // CryptoCurrency.dai, // CryptoCurrency.gusd, @@ -259,7 +260,7 @@ class ThorChainExchangeProvider extends ExchangeProvider { } String _normalizeCurrency(CryptoCurrency currency) { - final networkTitle = currency.tag == 'ETH' ? 'ETH' : currency.title; + final networkTitle = currency.tag == 'ETH' ? 'ETH' : currency.tag ?? currency.title; return '$networkTitle.${currency.title}'; } diff --git a/lib/exchange/provider/trocador_exchange_provider.dart b/lib/exchange/provider/trocador_exchange_provider.dart index f3a70b912..cdb0efba8 100644 --- a/lib/exchange/provider/trocador_exchange_provider.dart +++ b/lib/exchange/provider/trocador_exchange_provider.dart @@ -347,6 +347,8 @@ class TrocadorExchangeProvider extends ExchangeProvider { return 'TRC20'; case 'LN': return 'Lightning'; + case 'BSC': + return 'BEP20'; default: return tag.toLowerCase(); } From b3c20a5818df13a8c5e4f2839f14ca473f9aa5c0 Mon Sep 17 00:00:00 2001 From: Konstantin Ullrich Date: Fri, 27 Jun 2025 15:38:09 +0200 Subject: [PATCH 4/5] Generic fixes for payjoin (#2342) * feat: enhance Payjoin transaction details with block explorer link * feat: enhance Payjoin transaction details with block explorer link * fix: handle connectivity errors in Payjoin session operations --- cw_bitcoin/lib/bitcoin_wallet_addresses.dart | 4 ++++ .../lib/payjoin/payjoin_send_worker.dart | 4 ++-- .../payjoin_details_view_model.dart | 20 +++++++++++++++++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart index b33d722ab..d84d958be 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart @@ -67,6 +67,8 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S payjoinManager.resumeSessions(); } catch (e) { printV(e); + // Ignore Connectivity errors + if (!e.toString().contains("error sending request for url")) rethrow; } } @@ -79,6 +81,8 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S payjoinManager.spawnReceiver(receiver: currentPayjoinReceiver!); } catch (e) { printV(e); + // Ignore Connectivity errors + if (!e.toString().contains("error sending request for url")) rethrow; } } } diff --git a/cw_bitcoin/lib/payjoin/payjoin_send_worker.dart b/cw_bitcoin/lib/payjoin/payjoin_send_worker.dart index c11342800..7e85cc773 100644 --- a/cw_bitcoin/lib/payjoin/payjoin_send_worker.dart +++ b/cw_bitcoin/lib/payjoin/payjoin_send_worker.dart @@ -106,8 +106,8 @@ class PayjoinSenderWorker { sendPort.send({'type': PayjoinSenderRequestTypes.requestPosted}); return await postRequest.$2.processResponse(response: response); - } catch (e) { - throw PayjoinSessionError.unrecoverable('Send V1 payjoin error: $e'); + } catch (e, stack) { + throw PayjoinSessionError.unrecoverable('Send V1 payjoin error: $e, $stack'); } } diff --git a/lib/view_model/payjoin_details_view_model.dart b/lib/view_model/payjoin_details_view_model.dart index b19207373..7d63aaae3 100644 --- a/lib/view_model/payjoin_details_view_model.dart +++ b/lib/view_model/payjoin_details_view_model.dart @@ -4,7 +4,9 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/screens/trade_details/trade_details_list_card.dart'; import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart'; +import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; +import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart'; import 'package:cake_wallet/themes/core/theme_store.dart'; import 'package:cake_wallet/utils/date_formatter.dart'; import 'package:cw_core/payjoin_session.dart'; @@ -12,6 +14,7 @@ import 'package:cw_core/transaction_info.dart'; import 'package:flutter/widgets.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:mobx/mobx.dart'; +import 'package:url_launcher/url_launcher.dart'; part 'payjoin_details_view_model.g.dart'; @@ -40,7 +43,7 @@ abstract class PayjoinDetailsViewModelBase with Store { @observable late PayjoinSession payjoinSession; - final ObservableList items; + final ObservableList items; late final StreamSubscription listener; @@ -69,12 +72,25 @@ abstract class PayjoinDetailsViewModelBase with Store { title: S.current.error, value: payjoinSession.error!, ), - if (payjoinSession.txId?.isNotEmpty == true && transactionInfo != null) + if (payjoinSession.txId?.isNotEmpty == true && transactionInfo != null) ...[ StandartListItem( title: S.current.transaction_details_transaction_id, value: payjoinSession.txId!, key: ValueKey('standard_list_item_transaction_details_id_key'), + ), + BlockExplorerListItem( + title: S.current.view_in_block_explorer, + value: '${S.current.view_transaction_on}mempool.space', + onTap: () async { + try { + final uri = Uri.parse('https://mempool.cakewallet.com/tx/${payjoinSession.txId!}'); + if (await canLaunchUrl(uri)) + await launchUrl(uri, mode: LaunchMode.externalApplication); + } catch (e) {} + }, + key: ValueKey('block_explorer_list_item_wallet_type_key'), ) + ] ]); if (transactionInfo != null) { From 5aeb6b752291ee129084aad59ed99b3c54dad5b2 Mon Sep 17 00:00:00 2001 From: David Adegoke <64401859+Blazebrain@users.noreply.github.com> Date: Fri, 27 Jun 2025 15:53:46 +0100 Subject: [PATCH 5/5] Deuro Savings Error Handling (#2340) * feat(deuro): Enhance gas fee handling and error management for Deuro Savings Transactions. This change: - Introduces DeuroGasFeeException to handle insufficient ETH for gas fees. - Adds check for ETH balance before savings transactions to prevent failures due to insufficient funds. - Updates savings transaction methods to include error handling. - Adds UI feedback for transaction failures in DEuroSavingsPage. * Fix conflicts * Update cw_ethereum/lib/deuro/deuro_savings.dart Co-authored-by: Konstantin Ullrich --------- Co-authored-by: Omar Hatem Co-authored-by: Konstantin Ullrich --- cw_ethereum/lib/deuro/deuro_savings.dart | 127 +++++++++++++----- cw_evm/lib/evm_chain_exceptions.dart | 29 ++++ .../integrations/deuro/savings_page.dart | 20 +++ .../integrations/deuro_view_model.dart | 69 ++++++---- 4 files changed, 186 insertions(+), 59 deletions(-) diff --git a/cw_ethereum/lib/deuro/deuro_savings.dart b/cw_ethereum/lib/deuro/deuro_savings.dart index e5faa606a..bce05905c 100644 --- a/cw_ethereum/lib/deuro/deuro_savings.dart +++ b/cw_ethereum/lib/deuro/deuro_savings.dart @@ -2,6 +2,7 @@ import 'package:cw_core/crypto_currency.dart'; import 'package:cw_ethereum/deuro/deuro_savings_contract.dart'; import 'package:cw_ethereum/ethereum_wallet.dart'; import 'package:cw_evm/contract/erc20.dart'; +import 'package:cw_evm/evm_chain_exceptions.dart'; import 'package:cw_evm/evm_chain_transaction_priority.dart'; import 'package:cw_evm/pending_evm_chain_transaction.dart'; import 'package:web3dart/crypto.dart'; @@ -43,59 +44,111 @@ class DEuro { Future get approvedBalance => _dEuro.allowance(_address, _savingsGateway.self.address); - Future depositSavings( - BigInt amount, EVMChainTransactionPriority priority) async { - final signedTransaction = await _savingsGateway.save( - (amount: amount, frontendCode: hexToBytes(frontendCode)), - credentials: _wallet.evmChainPrivateKey, - ); + Future _checkEthBalanceForGasFees(EVMChainTransactionPriority priority) async { + final ethBalance = await _wallet.getWeb3Client()!.getBalance(_address); + final currentBalance = ethBalance.getInWei; - final fee = await _wallet.calculateActualEstimatedFeeForCreateTransaction( - amount: amount, + final gasFeesModel = await _wallet.calculateActualEstimatedFeeForCreateTransaction( + amount: BigInt.zero, contractAddress: _savingsGateway.self.address.hexEip55, receivingAddressHex: _savingsGateway.self.address.hexEip55, priority: priority, - data: _savingsGateway.self.abi.functions[17].encodeCall([amount, hexToBytes(frontendCode)]), + data: _savingsGateway.self.abi.functions[17] + .encodeCall([BigInt.zero, hexToBytes(frontendCode)]), ); - final sendTransaction = () => _wallet.getWeb3Client()!.sendRawTransaction(signedTransaction); + final estimatedGasFee = BigInt.from(gasFeesModel.estimatedGasFee); + final requiredBalance = estimatedGasFee; - return PendingEVMChainTransaction( + if (currentBalance < requiredBalance) { + throw DeuroGasFeeException( + requiredGasFee: requiredBalance, + currentBalance: currentBalance, + ); + } + } + + Future depositSavings( + BigInt amount, EVMChainTransactionPriority priority) async { + try { + await _checkEthBalanceForGasFees(priority); + + final signedTransaction = await _savingsGateway.save( + (amount: amount, frontendCode: hexToBytes(frontendCode)), + credentials: _wallet.evmChainPrivateKey, + ); + + final fee = await _wallet.calculateActualEstimatedFeeForCreateTransaction( + amount: amount, + contractAddress: _savingsGateway.self.address.hexEip55, + receivingAddressHex: _savingsGateway.self.address.hexEip55, + priority: priority, + data: _savingsGateway.self.abi.functions[17].encodeCall([amount, hexToBytes(frontendCode)]), + ); + + final sendTransaction = () => _wallet.getWeb3Client()!.sendRawTransaction(signedTransaction); + + return PendingEVMChainTransaction( sendTransaction: sendTransaction, signedTransaction: signedTransaction, fee: BigInt.from(fee.estimatedGasFee), amount: amount.toString(), - exponent: 18); + exponent: 18, + ); + } catch (e) { + if (e.toString().contains('insufficient funds for gas')) { + final ethBalance = await _wallet.getWeb3Client()!.getBalance(_address); + throw DeuroGasFeeException( + currentBalance: ethBalance.getInWei, + ); + } + rethrow; + } } Future withdrawSavings( BigInt amount, EVMChainTransactionPriority priority) async { - final signedTransaction = await _savingsGateway.withdraw( - (target: _address, amount: amount, frontendCode: hexToBytes(frontendCode)), - credentials: _wallet.evmChainPrivateKey, - ); + try { + await _checkEthBalanceForGasFees(priority); - final fee = await _wallet.calculateActualEstimatedFeeForCreateTransaction( - amount: amount, - contractAddress: _savingsGateway.self.address.hexEip55, - receivingAddressHex: _savingsGateway.self.address.hexEip55, - priority: priority, - data: _savingsGateway.self.abi.functions[17].encodeCall([amount, hexToBytes(frontendCode)]), - ); + final signedTransaction = await _savingsGateway.withdraw( + (target: _address, amount: amount, frontendCode: hexToBytes(frontendCode)), + credentials: _wallet.evmChainPrivateKey, + ); - final sendTransaction = () => _wallet.getWeb3Client()!.sendRawTransaction(signedTransaction); + final fee = await _wallet.calculateActualEstimatedFeeForCreateTransaction( + amount: amount, + contractAddress: _savingsGateway.self.address.hexEip55, + receivingAddressHex: _savingsGateway.self.address.hexEip55, + priority: priority, + data: _savingsGateway.self.abi.functions[17].encodeCall([amount, hexToBytes(frontendCode)]), + ); - return PendingEVMChainTransaction( - sendTransaction: sendTransaction, - signedTransaction: signedTransaction, - fee: BigInt.from(fee.estimatedGasFee), - amount: amount.toString(), - exponent: 18); + final sendTransaction = () => _wallet.getWeb3Client()!.sendRawTransaction(signedTransaction); + + return PendingEVMChainTransaction( + sendTransaction: sendTransaction, + signedTransaction: signedTransaction, + fee: BigInt.from(fee.estimatedGasFee), + amount: amount.toString(), + exponent: 18); + } catch (e) { + if (e.toString().contains('insufficient funds for gas')) { + final ethBalance = await _wallet.getWeb3Client()!.getBalance(_address); + throw DeuroGasFeeException( + currentBalance: ethBalance.getInWei, + ); + } + rethrow; + } } // Set an infinite approval to save gas in the future - Future enableSavings(EVMChainTransactionPriority priority) async => - (await _wallet.createApprovalTransaction( + Future enableSavings(EVMChainTransactionPriority priority) async { + try { + await _checkEthBalanceForGasFees(priority); + + return (await _wallet.createApprovalTransaction( BigInt.parse( 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', radix: 16, @@ -104,4 +157,14 @@ class DEuro { CryptoCurrency.deuro, priority, )) as PendingEVMChainTransaction; + } catch (e) { + if (e.toString().contains('insufficient funds for gas')) { + final ethBalance = await _wallet.getWeb3Client()!.getBalance(_address); + throw DeuroGasFeeException( + currentBalance: ethBalance.getInWei, + ); + } + rethrow; + } + } } diff --git a/cw_evm/lib/evm_chain_exceptions.dart b/cw_evm/lib/evm_chain_exceptions.dart index c7509a17f..19bb047ef 100644 --- a/cw_evm/lib/evm_chain_exceptions.dart +++ b/cw_evm/lib/evm_chain_exceptions.dart @@ -22,3 +22,32 @@ class EVMChainTransactionFeesException implements Exception { @override String toString() => exceptionMessage; } + +class DeuroGasFeeException implements Exception { + final String exceptionMessage; + final BigInt? requiredGasFee; + final BigInt? currentBalance; + + DeuroGasFeeException({ + this.requiredGasFee, + this.currentBalance, + }) : exceptionMessage = _buildMessage(requiredGasFee, currentBalance); + + static String _buildMessage(BigInt? requiredGasFee, BigInt? currentBalance) { + const baseMessage = 'Insufficient ETH for gas fees.'; + const addEthMessage = ' Please add ETH to your wallet to cover transaction fees.'; + + if (requiredGasFee != null) { + final requiredEth = (requiredGasFee / BigInt.from(10).pow(18)).toStringAsFixed(8); + final balanceInfo = currentBalance != null + ? ', Available: ${(currentBalance / BigInt.from(10).pow(18)).toStringAsFixed(8)} ETH' + : ''; + return '$baseMessage Required: ~$requiredEth ETH$balanceInfo.$addEthMessage'; + } + + return '$baseMessage$addEthMessage'; + } + + @override + String toString() => exceptionMessage; +} diff --git a/lib/src/screens/integrations/deuro/savings_page.dart b/lib/src/screens/integrations/deuro/savings_page.dart index a58578893..0b0f4941a 100644 --- a/lib/src/screens/integrations/deuro/savings_page.dart +++ b/lib/src/screens/integrations/deuro/savings_page.dart @@ -4,9 +4,11 @@ import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/integrations/deuro/widgets/interest_card_widget.dart'; import 'package:cake_wallet/src/screens/integrations/deuro/widgets/savings_card_widget.dart'; import 'package:cake_wallet/src/screens/integrations/deuro/widgets/savings_edit_sheet.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/bottom_sheet/confirm_sending_bottom_sheet_widget.dart'; import 'package:cake_wallet/src/widgets/bottom_sheet/info_bottom_sheet_widget.dart'; import 'package:cake_wallet/src/widgets/gradient_background.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/integrations/deuro_view_model.dart'; import 'package:cake_wallet/view_model/send/send_view_model_state.dart'; import 'package:cw_core/crypto_currency.dart'; @@ -190,6 +192,24 @@ class DEuroSavingsPage extends BasePage { ); }); } + + if (state is FailureState) { + WidgetsBinding.instance.addPostFrameCallback((_) async { + if (!context.mounted) return; + + await showPopUp( + context: context, + builder: (BuildContext popupContext) { + return AlertWithOneAction( + alertTitle: S.of(popupContext).error, + alertContent: state.error, + buttonText: S.of(popupContext).ok, + buttonAction: () => Navigator.of(popupContext).pop(), + ); + }, + ); + }); + } }); _isReactionsSet = true; diff --git a/lib/view_model/integrations/deuro_view_model.dart b/lib/view_model/integrations/deuro_view_model.dart index 09f9a363c..eca3c2376 100644 --- a/lib/view_model/integrations/deuro_view_model.dart +++ b/lib/view_model/integrations/deuro_view_model.dart @@ -46,10 +46,8 @@ abstract class DEuroViewModelBase with Store { @action Future reloadSavingsUserData() async { - final savingsBalanceRaw = - ethereum!.getDEuroSavingsBalance(_appStore.wallet!); - final accruedInterestRaw = - ethereum!.getDEuroAccruedInterest(_appStore.wallet!); + final savingsBalanceRaw = ethereum!.getDEuroSavingsBalance(_appStore.wallet!); + final accruedInterestRaw = ethereum!.getDEuroAccruedInterest(_appStore.wallet!); approvedTokens = await ethereum!.getDEuroSavingsApproved(_appStore.wallet!); @@ -63,56 +61,73 @@ abstract class DEuroViewModelBase with Store { @action Future reloadInterestRate() async { - final interestRateRaw = - await ethereum!.getDEuroInterestRate(_appStore.wallet!); + final interestRateRaw = await ethereum!.getDEuroInterestRate(_appStore.wallet!); interestRate = (interestRateRaw / BigInt.from(10000)).toString(); } @action Future prepareApproval() async { - final priority = _appStore.settingsStore.priority[WalletType.ethereum]!; - approvalTransaction = - await ethereum!.enableDEuroSaving(_appStore.wallet!, priority); + try { + state = TransactionCommitting(); + final priority = _appStore.settingsStore.priority[WalletType.ethereum]!; + approvalTransaction = await ethereum!.enableDEuroSaving(_appStore.wallet!, priority); + state = InitialExecutionState(); + } catch (e) { + state = FailureState(e.toString()); + } } @action Future prepareSavingsEdit(String amountRaw, bool isAdding) async { - final amount = BigInt.from(num.parse(amountRaw) * pow(10, 18)); - final priority = _appStore.settingsStore.priority[WalletType.ethereum]!; - transaction = await (isAdding - ? ethereum!.addDEuroSaving(_appStore.wallet!, amount, priority) - : ethereum!.removeDEuroSaving(_appStore.wallet!, amount, priority)); + try { + state = TransactionCommitting(); + final amount = BigInt.from(num.parse(amountRaw) * pow(10, 18)); + final priority = _appStore.settingsStore.priority[WalletType.ethereum]!; + transaction = await (isAdding + ? ethereum!.addDEuroSaving(_appStore.wallet!, amount, priority) + : ethereum!.removeDEuroSaving(_appStore.wallet!, amount, priority)); + state = InitialExecutionState(); + } catch (e) { + state = FailureState(e.toString()); + } } - Future prepareCollectInterest() => - prepareSavingsEdit(accruedInterest, false); + Future prepareCollectInterest() => prepareSavingsEdit(accruedInterest, false); @action Future commitTransaction() async { if (transaction != null) { - state = TransactionCommitting(); - await transaction!.commit(); - transaction = null; - reloadSavingsUserData(); - state = TransactionCommitted(); + try { + state = TransactionCommitting(); + await transaction!.commit(); + transaction = null; + reloadSavingsUserData(); + state = TransactionCommitted(); + } catch (e) { + state = FailureState(e.toString()); + } } } @action Future commitApprovalTransaction() async { if (approvalTransaction != null) { - state = TransactionCommitting(); - await approvalTransaction!.commit(); - approvalTransaction = null; - reloadSavingsUserData(); - state = TransactionCommitted(); + try { + state = TransactionCommitting(); + await approvalTransaction!.commit(); + approvalTransaction = null; + reloadSavingsUserData(); + state = TransactionCommitted(); + } catch (e) { + state = FailureState(e.toString()); + } } } @action void dismissTransaction() { - transaction == null; + transaction = null; approvalTransaction = null; state = InitialExecutionState(); }