Cleanup and Bug fixes

This commit is contained in:
OmarHatem
2025-10-27 16:34:49 +01:00
parent 97c976d26c
commit 7b9cd9ec2b
7 changed files with 163 additions and 158 deletions
+24 -16
View File
@@ -165,25 +165,33 @@ class PayjoinManager {
return initReceiver(address);
}
Future<Receiver> initReceiver(String address, [bool isTestnet = false]) async {
final ohttpKeys = await PayjoinUri.fetchOhttpKeys(
ohttpRelay: await randomOhttpRelayUrl(),
payjoinDirectory: payjoinDirectoryUrl,
);
Future<Receiver> initReceiver(String address, [bool isTestnet = false, int retryCount = 0]) async {
try {
final ohttpKeys = await PayjoinUri.fetchOhttpKeys(
ohttpRelay: await randomOhttpRelayUrl(),
payjoinDirectory: payjoinDirectoryUrl,
);
final newReceiver = await NewReceiver.create(
address: address,
network: isTestnet ? Network.testnet : Network.bitcoin,
directory: payjoinDirectoryUrl,
ohttpKeys: ohttpKeys,
);
final persister = PayjoinReceiverPersister.impl();
final receiverToken = await newReceiver.persist(persister: persister);
final receiver = await Receiver.load(persister: persister, token: receiverToken);
final newReceiver = await NewReceiver.create(
address: address,
network: isTestnet ? Network.testnet : Network.bitcoin,
directory: payjoinDirectoryUrl,
ohttpKeys: ohttpKeys,
);
final persister = PayjoinReceiverPersister.impl();
final receiverToken = await newReceiver.persist(persister: persister);
final receiver = await Receiver.load(persister: persister, token: receiverToken);
await _payjoinStorage.insertReceiverSession(receiver, _wallet.id);
await _payjoinStorage.insertReceiverSession(receiver, _wallet.id);
return receiver;
return receiver;
} catch (e) {
if (e.toString().contains("error sending request for url") && retryCount < 5) {
return initReceiver(address, isTestnet, ++retryCount);
} else {
rethrow;
}
}
}
Future<void> spawnReceiver({
+2
View File
@@ -261,6 +261,8 @@ abstract class NanoWalletBase
}
}
Future<void> updateTransactionsHistory() async => await updateTransactions();
Future<bool> updateTransactions() async {
try {
if (_isTransactionUpdating) {
+31 -31
View File
@@ -231,46 +231,46 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/wakelock_plus/ios"
SPEC CHECKSUMS:
bitbox_flutter: 9505732798041c413152669751beeaecc5fe400f
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
bitbox_flutter: 506f80b961ddf646b0d80cef9f6eadaab96d91b0
connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d
CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90
cw_decred: a02cf30175a46971c1e2fa22c48407534541edc6
cw_mweb: 3aea2fb35b2bd04d8b2d21b83216f3b8fb768d85
device_display_brightness: 04374ebd653619292c1d996f00f42877ea19f17f
device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89
devicelocale: bd64aa714485a8afdaded0892c1e7d5b7f680cf8
cw_decred: 9c0e1df74745b51a1289ec5e91fb9e24b68fa14a
cw_mweb: 22cd01dfb8ad2d39b15332006f22046aaa8352a3
device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
dnssec_proof: d461cac7bd3301eb7447f87936745a0c1ae0a67e
fast_scanner: 2cb1ad3e69e645e9980fb4961396ce5804caa3e3
file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517
fast_scanner: 44c00940355a51258cd6c2085734193cd23d95bc
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
flutter_local_authentication: 989278c681612f1ee0e36019e149137f114b9d7f
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
flutter_mailer: 3a8cd4f36c960fb04528d5471097270c19fec1c4
flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
in_app_review: 7dd1ea365263f834b8464673f9df72c80c17c937
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
flutter_local_authentication: 1172a4dd88f6306dadce067454e2c4caf07977bb
flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f
flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
in_app_review: 436034b18594851a7328d7f1c2ed5ec235b79cfc
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
payjoin_flutter: d9d4c8aa16bd5dfedb9b21d0edc8199e0187d96e
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
reown_yttrium: cee334ade64725b1d83f7b34c706a6aae2696d58
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
reown_yttrium: c0e87e5965fa60a3559564cc35cffbba22976089
SDWebImage: 9f177d83116802728e122410fb25ad88f5c7608a
sensitive_clipboard: 161e9abc3d56b3131309d8a321eb4690a803c16b
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sp_scanner: b1bc9321690980bdb44bba7ec85d5543e716d1b5
sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
torch_dart: f4620705d10f05492fab047f2fa1c3a600e7d17d
uni_links: ed8c961e47ed9ce42b6d91e1de8049e38a4b3152
universal_ble: ff19787898040d721109c6324472e5dd4bc86adc
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
torch_dart: d2cf778332cc6e6a3b362dcf45e4dde52bc34e35
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
wakelock_plus: 76957ab028e12bfa4e66813c99e46637f367fc7e
YttriumWrapper: 31e937fe9fbe0f1314d2ca6be9ce9b379a059966
PODFILE CHECKSUM: 5296465b1c6d14d506230356756826012f65d97a
+1 -17
View File
@@ -629,7 +629,7 @@ class ExchangePage extends BasePage {
void _onCurrencyChange(CryptoCurrency currency, ExchangeViewModel exchangeViewModel,
GlobalKey<ExchangeCardState> key) {
final isCurrentTypeWallet = currency == exchangeViewModel.wallet.currency;
final isCurrentTypeWallet = exchangeViewModel.isDepositSameCurrency;
key.currentState!.changeSelectedCurrency(currency);
key.currentState!.changeWalletName(isCurrentTypeWallet ? exchangeViewModel.wallet.name : '');
@@ -708,22 +708,6 @@ class ExchangePage extends BasePage {
isMoneroWallet: exchangeViewModel.isMoneroWallet,
currencies: exchangeViewModel.depositCurrencies,
onCurrencySelected: (currency) {
// FIXME: need to move it into view model
if (currency == CryptoCurrency.xmr &&
exchangeViewModel.wallet.type != WalletType.monero) {
showPopUp<void>(
context: context,
builder: (dialogContext) {
return AlertWithOneAction(
alertTitle: S.of(context).error,
alertContent: S.of(context).exchange_incorrect_current_wallet_for_xmr,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(dialogContext).pop(),
);
});
return;
}
exchangeViewModel.changeDepositCurrency(currency: currency);
},
currencyButtonColor: Colors.transparent,
+3 -1
View File
@@ -243,7 +243,9 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
PaymentRequest paymentRequest,
PaymentFlowResult result,
) async {
Navigator.of(context).pop();
if (context.mounted && Navigator.of(context).canPop()) {
Navigator.of(context).pop();
}
if (result.wallet != null) {
walletSwitcherViewModel.selectWallet(result.wallet!);
@@ -150,12 +150,11 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
}
});
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isDepositAddressEnabled = !(isDepositSameCurrency);
depositAmount = '';
receiveAmount = '';
receiveAddress = '';
depositAddress =
depositCurrency == wallet.currency ? wallet.walletAddresses.addressForExchange : '';
depositAddress = isDepositSameCurrency ? wallet.walletAddresses.addressForExchange : '';
provider = providerList.firstOrNull;
final initialProvider = provider;
@@ -190,6 +189,11 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
}
}
bool get isDepositSameCurrency =>
depositCurrency == wallet.currency ||
depositCurrency.tag == wallet.currency.tag ||
depositCurrency.tag == wallet.currency.title;
bool get isElectrumWallet => [
WalletType.bitcoin,
WalletType.litecoin,
@@ -412,10 +416,16 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
@action
void changeDepositCurrency({required CryptoCurrency currency}) {
print("@@@@@@@@");
print(currency);
print(currency.tag);
print(currency.title);
print(wallet.currency.tag);
print(wallet.currency.title);
depositCurrency = currency;
isFixedRateMode = false;
_onPairChange();
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isDepositAddressEnabled = !(isDepositSameCurrency);
}
@action
@@ -423,7 +433,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
receiveCurrency = currency;
isFixedRateMode = false;
_onPairChange();
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isDepositAddressEnabled = !(isDepositSameCurrency);
}
@action
@@ -534,12 +544,11 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
_providers.map(
(element) => element
.fetchRate(
from: depositCurrency,
to: receiveCurrency,
amount: amount,
isFixedRateMode: isFixedRateMode,
isReceiveAmount: isFixedRateMode
)
from: depositCurrency,
to: receiveCurrency,
amount: amount,
isFixedRateMode: isFixedRateMode,
isReceiveAmount: isFixedRateMode)
.timeout(
Duration(seconds: 7),
onTimeout: () => 0.0,
+82 -82
View File
@@ -730,46 +730,85 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
}
}
Future<void> _handleOcpRequest() async {
if (OpenCryptoPayService.requiresClientCommit(selectedCryptoCurrency)) {
await pendingTransaction!.commit();
}
await _ocpService.commitOpenCryptoPayRequest(
pendingTransaction!.hex,
txId: pendingTransaction!.id,
request: ocpRequest!,
asset: selectedCryptoCurrency,
);
}
Future<void> _commitApprovalTransaction() async {
if (_pendingApprovalTx != null) {
await _pendingApprovalTx!.commit();
_pendingApprovalTx = null;
// Small pause to ensure allowance is indexed
await Future.delayed(const Duration(milliseconds: 300));
}
await pendingTransaction!.commit();
_isSwapsXYZCallDataTx = false;
}
Future<void> _commitUR(BuildContext context) async {
final urstr = await pendingTransaction!.commitUR();
final result = await Navigator.of(context).pushNamed(Routes.urqrAnimatedPage, arguments: urstr);
if (result == null) {
throw "Canceled by user";
}
}
@action
Future<void> commitTransaction(BuildContext context) async {
if (pendingTransaction == null) {
throw Exception("Pending transaction doesn't exist. It should not be happened.");
}
if (ocpRequest != null) {
try {
state = TransactionCommitting();
if (OpenCryptoPayService.requiresClientCommit(selectedCryptoCurrency)) {
if (ocpRequest != null) {
await _handleOcpRequest();
} else if (_isSwapsXYZCallDataTx) {
// Swaps.xyz approval (if any), then commit the prebuilt router tx
await _commitApprovalTransaction();
} else if (pendingTransaction!.shouldCommitUR()) {
await _commitUR(context);
} else {
await pendingTransaction!.commit();
}
await _ocpService.commitOpenCryptoPayRequest(
pendingTransaction!.hex,
txId: pendingTransaction!.id,
request: ocpRequest!,
asset: selectedCryptoCurrency,
);
state = TransactionCommitted();
return;
}
// Swaps.xyz approval (if any), then commit the prebuilt router tx
if (_isSwapsXYZCallDataTx) {
if (_pendingApprovalTx != null) {
await _pendingApprovalTx!.commit();
_pendingApprovalTx = null;
// Small pause to ensure allowance is indexed
await Future.delayed(const Duration(milliseconds: 300));
// Immediate transaction update for EVM chains, Solana, Tron, and Nano
if (isEVMWallet ||
[WalletType.solana, WalletType.tron, WalletType.nano].contains(walletType)) {
Future.delayed(Duration(seconds: 4), () async {
try {
await wallet.updateTransactionsHistory();
} catch (e) {
printV('Failed to update transactions after send: $e');
}
});
}
await pendingTransaction!.commit();
_isSwapsXYZCallDataTx = false;
state = TransactionCommitted();
return; // skip the regular flow below
if (pendingTransaction!.id.isNotEmpty) {
_addTransactionDescription();
}
final sharedPreferences = await SharedPreferences.getInstance();
await sharedPreferences.setString(PreferencesKey.backgroundSyncLastTrigger(wallet.name),
DateTime.now().add(Duration(minutes: 1)).toIso8601String());
} catch (e) {
state = FailureState(translateErrorMessage(e, wallet.type, wallet.currency));
}
}
Future<void> _addTransactionDescription() async {
String address = outputs.fold('', (acc, value) {
return value.isParsedAddress
? '$acc${value.address}\n${value.extractedAddress}\n\n'
@@ -782,65 +821,26 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
note = note.trim();
try {
state = TransactionCommitting();
if (pendingTransaction!.shouldCommitUR()) {
final urstr = await pendingTransaction!.commitUR();
final result =
await Navigator.of(context).pushNamed(Routes.urqrAnimatedPage, arguments: urstr);
if (result == null) {
state = FailureState("Canceled by user");
return;
}
} else {
await pendingTransaction!.commit();
}
if (walletType == WalletType.nano) {
nano!.updateTransactions(wallet);
}
// Immediate transaction update for EVM chains, Solana, and Tron
if (isEVMWallet || walletType == WalletType.solana || walletType == WalletType.tron) {
Future.delayed(Duration(seconds: 4), () async {
try {
await wallet.updateTransactionsHistory();
} catch (e) {
printV('Failed to update transactions after send: $e');
}
});
}
if (pendingTransaction!.id.isNotEmpty) {
TransactionInfo? tx;
if (walletType == WalletType.monero) {
await Future.delayed(Duration(milliseconds: 450));
await wallet.fetchTransactions();
final txhistory = monero!.getTransactionHistory(wallet);
tx = txhistory.transactions.values.last;
}
final descriptionKey = '${pendingTransaction!.id}_${wallet.walletAddresses.primaryAddress}';
_settingsStore.shouldSaveRecipientAddress
? await transactionDescriptionBox.add(TransactionDescription(
id: descriptionKey,
recipientAddress: address,
transactionNote: note,
transactionKey: tx?.additionalInfo["key"] as String?,
))
: await transactionDescriptionBox.add(TransactionDescription(
id: descriptionKey,
transactionNote: note,
transactionKey: tx?.additionalInfo["key"] as String?,
));
}
final sharedPreferences = await SharedPreferences.getInstance();
await sharedPreferences.setString(PreferencesKey.backgroundSyncLastTrigger(wallet.name),
DateTime.now().add(Duration(minutes: 1)).toIso8601String());
state = TransactionCommitted();
} catch (e) {
state = FailureState(translateErrorMessage(e, wallet.type, wallet.currency));
TransactionInfo? tx;
if (walletType == WalletType.monero) {
await Future.delayed(Duration(milliseconds: 450));
await wallet.fetchTransactions();
final txhistory = monero!.getTransactionHistory(wallet);
tx = txhistory.transactions.values.last;
}
final descriptionKey = '${pendingTransaction!.id}_${wallet.walletAddresses.primaryAddress}';
_settingsStore.shouldSaveRecipientAddress
? await transactionDescriptionBox.add(TransactionDescription(
id: descriptionKey,
recipientAddress: address,
transactionNote: note,
transactionKey: tx?.additionalInfo["key"] as String?,
))
: await transactionDescriptionBox.add(TransactionDescription(
id: descriptionKey,
transactionNote: note,
transactionKey: tx?.additionalInfo["key"] as String?,
));
}
Object _credentials([ExchangeProvider? provider]) {