Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ enum _Screen { input, confirm, progress }

class _ClaimRewardsDialogState extends State<_ClaimRewardsDialog> {
final _addressController = TextEditingController();
final _claimService = WormholeClaimService();
final _claimService = WormholeSendService();
final _walletService = MinerWalletService();
final _settingsService = MinerSettingsService();

Expand Down
28 changes: 28 additions & 0 deletions mobile-app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -2693,5 +2693,33 @@
"type": "int"
}
}
},
"encryptedSendFeeLabel": "Privacy fee",
"@encryptedSendFeeLabel": {
"description": "Fee label for encrypted sends (wormhole volume fee)"
},
"encryptedSendAmountStep": "Use steps of 0.01 QUAN",
"@encryptedSendAmountStep": {
"description": "Shown when an encrypted send amount is not a multiple of 0.01 QUAN"
},
"encryptedSendMinimum": "Encrypted sends must move at least 0.1 QUAN",
"@encryptedSendMinimum": {
"description": "Shown when an encrypted send falls below the chain's minimum exit amount"
},
"encryptedSendProgressTitle": "Sending Privately...",
"@encryptedSendProgressTitle": {
"description": "App bar title while an encrypted send is proving/submitting"
},
"encryptedSendFailedTitle": "Send Failed",
"@encryptedSendFailedTitle": {
"description": "App bar title when an encrypted send failed"
},
"encryptedSendCancelledTitle": "Send Cancelled",
"@encryptedSendCancelledTitle": {
"description": "App bar title when an encrypted send was cancelled"
},
"encryptedSendingLabel": "SENDING",
"@encryptedSendingLabel": {
"description": "Status header label on encrypted send progress"
}
}
9 changes: 8 additions & 1 deletion mobile-app/lib/l10n/app_id.arb
Original file line number Diff line number Diff line change
Expand Up @@ -610,5 +610,12 @@
"redeemRetry": "Coba Lagi",
"redeemClose": "Tutup",
"redeemDone": "Selesai",
"redeemSuccessBanner": "{amount} ditukar dalam {count} batch"
"redeemSuccessBanner": "{amount} ditukar dalam {count} batch",
"encryptedSendFeeLabel": "Biaya privasi",
"encryptedSendAmountStep": "Gunakan kelipatan 0,01 QUAN",
"encryptedSendMinimum": "Pengiriman terenkripsi minimal 0,1 QUAN",
"encryptedSendProgressTitle": "Mengirim Secara Privat...",
"encryptedSendFailedTitle": "Pengiriman Gagal",
"encryptedSendCancelledTitle": "Pengiriman Dibatalkan",
"encryptedSendingLabel": "MENGIRIM"
}
42 changes: 42 additions & 0 deletions mobile-app/lib/l10n/app_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3451,6 +3451,48 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'{amount} redeemed in {count} batch(es)'**
String redeemSuccessBanner(String amount, int count);

/// Fee label for encrypted sends (wormhole volume fee)
///
/// In en, this message translates to:
/// **'Privacy fee'**
String get encryptedSendFeeLabel;

/// Shown when an encrypted send amount is not a multiple of 0.01 QUAN
///
/// In en, this message translates to:
/// **'Use steps of 0.01 QUAN'**
String get encryptedSendAmountStep;

/// Shown when an encrypted send falls below the chain's minimum exit amount
///
/// In en, this message translates to:
/// **'Encrypted sends must move at least 0.1 QUAN'**
String get encryptedSendMinimum;

/// App bar title while an encrypted send is proving/submitting
///
/// In en, this message translates to:
/// **'Sending Privately...'**
String get encryptedSendProgressTitle;

/// App bar title when an encrypted send failed
///
/// In en, this message translates to:
/// **'Send Failed'**
String get encryptedSendFailedTitle;

/// App bar title when an encrypted send was cancelled
///
/// In en, this message translates to:
/// **'Send Cancelled'**
String get encryptedSendCancelledTitle;

/// Status header label on encrypted send progress
///
/// In en, this message translates to:
/// **'SENDING'**
String get encryptedSendingLabel;
}

class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
Expand Down
21 changes: 21 additions & 0 deletions mobile-app/lib/l10n/app_localizations_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1860,4 +1860,25 @@ class AppLocalizationsEn extends AppLocalizations {
String redeemSuccessBanner(String amount, int count) {
return '$amount redeemed in $count batch(es)';
}

@override
String get encryptedSendFeeLabel => 'Privacy fee';

@override
String get encryptedSendAmountStep => 'Use steps of 0.01 QUAN';

@override
String get encryptedSendMinimum => 'Encrypted sends must move at least 0.1 QUAN';

@override
String get encryptedSendProgressTitle => 'Sending Privately...';

@override
String get encryptedSendFailedTitle => 'Send Failed';

@override
String get encryptedSendCancelledTitle => 'Send Cancelled';

@override
String get encryptedSendingLabel => 'SENDING';
}
21 changes: 21 additions & 0 deletions mobile-app/lib/l10n/app_localizations_id.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1857,4 +1857,25 @@ class AppLocalizationsId extends AppLocalizations {
String redeemSuccessBanner(String amount, int count) {
return '$amount ditukar dalam $count batch';
}

@override
String get encryptedSendFeeLabel => 'Biaya privasi';

@override
String get encryptedSendAmountStep => 'Gunakan kelipatan 0,01 QUAN';

@override
String get encryptedSendMinimum => 'Pengiriman terenkripsi minimal 0,1 QUAN';

@override
String get encryptedSendProgressTitle => 'Mengirim Secara Privat...';

@override
String get encryptedSendFailedTitle => 'Pengiriman Gagal';

@override
String get encryptedSendCancelledTitle => 'Pengiriman Dibatalkan';

@override
String get encryptedSendingLabel => 'MENGIRIM';
}
41 changes: 40 additions & 1 deletion mobile-app/lib/providers/wallet_providers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:flutter_riverpod/legacy.dart';
import 'package:quantus_sdk/quantus_sdk.dart';
import 'package:resonance_network_wallet/providers/account_providers.dart';
import 'package:resonance_network_wallet/providers/l10n_provider.dart';
import 'package:resonance_network_wallet/providers/remote_config_provider.dart';
import 'package:resonance_network_wallet/providers/pending_multisig_cancellations_provider.dart';
import 'package:resonance_network_wallet/providers/pending_multisig_creations_provider.dart';
import 'package:resonance_network_wallet/providers/pending_multisig_executions_provider.dart';
Expand Down Expand Up @@ -69,6 +70,40 @@ final wormholeUtxoServiceProvider = Provider<WormholeUtxoService>((ref) {
return WormholeUtxoService();
});

/// One encrypted-account service per wallet: caches derived wormhole key pairs
/// and owns the persisted next-index / pending-spend state.
final encryptedAccountServiceProvider = Provider.family<EncryptedAccountService, int>((ref, walletIndex) {
return EncryptedAccountService(
walletIndex: walletIndex,
getMnemonic: () => ref.read(settingsServiceProvider).getMnemonic(walletIndex),
);
});

/// Discovered UTXO set + pending change for a wallet's encrypted account.
final encryptedStateProvider = FutureProvider.family<EncryptedAccountState, int>((ref, walletIndex) {
return ref.watch(encryptedAccountServiceProvider(walletIndex)).load();
});

final encryptedBalanceProvider = Provider.family<AsyncValue<BigInt>, int>((ref, walletIndex) {
return ref.watch(encryptedStateProvider(walletIndex)).whenData((s) => s.balance);
});

/// Exact max sendable (inputs net of the wormhole volume fee).
final encryptedSpendableProvider = Provider.family<AsyncValue<BigInt>, int>((ref, walletIndex) {
return ref.watch(encryptedStateProvider(walletIndex)).whenData((s) => s.maxSendable);
});

bool isEncryptedAccount(BaseAccount? account) => account is Account && account.accountType == AccountType.encrypted;

/// Backfills the per-wallet encrypted (wormhole) account for every software
/// wallet, gated by the feature flag. Idempotent; returns true if any were
/// added (callers invalidate [accountsProvider] then).
Future<bool> ensureEncryptedAccounts(WidgetRef ref) async {
if (!ref.read(remoteConfigProvider).enableEncryptedAccount) return false;
final name = ref.read(l10nProvider).createAccountEncryptedDefaultName;
return ref.read(accountsServiceProvider).ensureEncryptedAccountsForSoftwareWallets(name: name);
}

final isHighSecurityProvider = FutureProvider.family<bool, Account>((ref, account) async {
final highSecurityService = ref.watch(highSecurityServiceProvider);
return await highSecurityService.isHighSecurity(account);
Expand Down Expand Up @@ -117,7 +152,11 @@ final balanceProviderRaw = Provider<AsyncValue<BigInt>>((ref) {
if (activeAccount == null) {
return AsyncValue.data(BigInt.zero);
}
return ref.watch(balanceProviderFamily(activeAccount.account.accountId));
final account = activeAccount.account;
if (isEncryptedAccount(account)) {
return ref.watch(encryptedBalanceProvider((account as Account).walletIndex));
}
return ref.watch(balanceProviderFamily(account.accountId));
},
loading: () => const AsyncValue.loading(),
error: (err, stack) => AsyncValue.error(err, stack),
Expand Down
26 changes: 18 additions & 8 deletions mobile-app/lib/shared/utils/polling_refresh_scope.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,29 @@ Set<String> reconciliationAccountIds({

/// Invalidates balance for the active account only.
void invalidateActiveAccountBalance(Ref ref) {
final accountId = activeAccountId(ref);
if (accountId == null) return;
final account = ref.read(activeAccountProvider).value?.account;
if (account == null) return;

ref.invalidate(balanceProviderFamily(accountId));
if (isEncryptedAccount(account)) {
ref.invalidate(encryptedStateProvider((account as Account).walletIndex));
return;
}
ref.invalidate(balanceProviderFamily(account.accountId));
}

/// Invalidates the active account balance and waits for it to reload.
Future<void> refreshActiveAccountBalance(Ref ref) async {
final accountId = activeAccountId(ref);
if (accountId == null) return;

ref.invalidate(balanceProviderFamily(accountId));
await ref.read(balanceProviderFamily(accountId).future);
final account = ref.read(activeAccountProvider).value?.account;
if (account == null) return;

if (isEncryptedAccount(account)) {
final provider = encryptedStateProvider((account as Account).walletIndex);
ref.invalidate(provider);
await ref.read(provider.future);
return;
}
ref.invalidate(balanceProviderFamily(account.accountId));
await ref.read(balanceProviderFamily(account.accountId).future);
}

/// Invalidates balance for the given account IDs.
Expand Down
Loading
Loading