Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
7ec8f85
feat(faucet): migrate has faucet check to the SDK extension
takenagain Oct 20, 2025
7988160
fix(auth): show seed backup banner in mobile view
takenagain Oct 24, 2025
44ca2fa
fix: dismiss keyboard on scroll for fiat and swap inputs
takenagain Oct 24, 2025
51e04aa
fix(coins-list): alignment and spacing of text in the active coins list
takenagain Oct 24, 2025
af47946
fix(fiat-onramp): text alignment and scaling for longer names
takenagain Oct 24, 2025
bf8774c
fix(fiat-onramp): add komodo and sandbox domains to whitelist
takenagain Oct 24, 2025
ffe74db
Merge remote-tracking branch 'origin/main' into hotfix/fiat-form-and-…
takenagain Oct 24, 2025
a2237c1
fix(fiat-onramp): disable overly restrictive CSP with limited platfor…
takenagain Oct 24, 2025
55174f3
refactor: remove unused widget and update enum docs
takenagain Oct 24, 2025
14b0157
Merge branch 'dev' into hotfix/fiat-form-and-banner
CharlVS Oct 24, 2025
6e867da
refactor(fiat-onramp): deprecate legacy validation and move emit down
takenagain Oct 24, 2025
701d3cc
feat(pubkeys): prefer cached pubkeys before RPC across app; add post-…
CharlVS Oct 26, 2025
9bdee62
chore(format): run dart format on pubkey cache call-sites and taker d…
CharlVS Oct 26, 2025
c9c3434
Merge branch 'dev' into perf/3238-reduce-rpc-spam
CharlVS Oct 26, 2025
e5e0d86
fix: fix analysis type warning
CharlVS Oct 26, 2025
f0a6b0d
chore(sdk): bump submodule to include local-auth test fix
CharlVS Oct 26, 2025
4f93114
hide custom seed toggle unless bip39 validation fails
smk762 Oct 27, 2025
b033188
clear errmsg before revalidation, do not duplicate errmsgs
smk762 Oct 27, 2025
5ffab50
Merge branch 'dev' into feat/tendermint-faucet-coins
takenagain Oct 27, 2025
00d19ab
Merge branch 'dev' into perf/3238-reduce-rpc-spam
CharlVS Oct 27, 2025
ae8eb92
perf(rpc): reduce MM2 RPC spam via SDK cache and UI debouncing
CharlVS Oct 27, 2025
6e83be9
chore: update SDK submodule with streaming type safety improvements
CharlVS Oct 27, 2025
d8eef4f
chore: update SDK submodule with event streaming manager
CharlVS Oct 27, 2025
49d1756
chore: roll SDK
CharlVS Oct 27, 2025
e472aad
chore: update sdk submodule with review feedback fixes
CharlVS Oct 27, 2025
8c6fb84
chore: update SDK submodule with shutdown event streaming optimization
CharlVS Oct 27, 2025
909bf11
chore: update sdk submodule with new wallet optimization
CharlVS Oct 27, 2025
051ac42
chore: update sdk submodule with imported wallet fix
CharlVS Oct 27, 2025
19537e0
feat(withdraw): append fiat value to amount and fee
takenagain Oct 27, 2025
4bf37d5
Merge branch 'dev' of https://github.com/KomodoPlatform/komodo-wallet…
CharlVS Oct 27, 2025
6047895
chore: roll SDK
CharlVS Oct 27, 2025
fbd4db4
(TEMP): Comment out breaking changes from merge
CharlVS Oct 27, 2025
6a2237b
chore: roll SDK
CharlVS Oct 27, 2025
b9be4b8
update wording for consistency
smk762 Oct 28, 2025
f2d40bb
Merge branch 'dev' into hide-custom-seed-option
smk762 Oct 28, 2025
fb5738f
chore: roll SDK
CharlVS Oct 28, 2025
3d12c67
chore: roll SDK with activation cache fix
CharlVS Oct 28, 2025
2ecaf56
chore: roll SDK with asset ID streaming fix
CharlVS Oct 28, 2025
812f939
chore: roll SDK
CharlVS Oct 28, 2025
5e35d03
Merge branch 'dev' into perf/3238-reduce-rpc-spam
CharlVS Oct 28, 2025
d920efe
Update lib/bloc/fiat/fiat_onramp_form/fiat_form_bloc.dart
CharlVS Oct 28, 2025
2c8c4c4
fix(coins): add check for already-activated assets before activation
CharlVS Oct 28, 2025
2bbe79a
activate fiat ramp selected via CoinsRepo ot reach CoinsBloc
smk762 Oct 28, 2025
e89068d
restore BTC-segwit to auto-activation list
smk762 Oct 28, 2025
95104f6
Fix web build error due to `Platform` unsupported
smk762 Oct 28, 2025
193140f
avoid null check error on unban_pubkey button press
smk762 Oct 28, 2025
7428040
Merge branch 'dev' into hide-custom-seed-option
smk762 Oct 28, 2025
cfaa180
Merge branch 'dev' into align-activation=state
smk762 Oct 28, 2025
89e62fc
style(withdraw): add vertical layout for devices with limited width
takenagain Oct 28, 2025
257e0af
Merge remote-tracking branch 'origin/dev' into fix/withdraw-form-values
takenagain Oct 28, 2025
5bac9d1
Merge branch 'dev' into hide-custom-seed-option
smk762 Oct 28, 2025
514c1f2
Merge branch 'dev' into align-activation=state
smk762 Oct 28, 2025
9c4674c
Merge branch 'dev' into fix-unban_pubkeys-null-check-error
smk762 Oct 28, 2025
9f2afdb
Merge branch 'dev' into fix/withdraw-form-values
takenagain Oct 28, 2025
fc2f907
Update lib/shared/widgets/asset_amount_with_fiat.dart
CharlVS Oct 28, 2025
491e9f9
chore(sdk): bump submodule to include stream type normalization and f…
CharlVS Oct 28, 2025
0494442
Merge branch 'dev' of https://github.com/KomodoPlatform/komodo-wallet…
CharlVS Oct 28, 2025
bb099db
fix: unnecessary activation cache invalidation
CharlVS Oct 28, 2025
5b416f3
Merge branch 'dev' into hotfix/fiat-form-and-banner
takenagain Oct 28, 2025
9900372
fix: show unconfirmed transactions first in list
CharlVS Oct 28, 2025
02e3f2d
revert toggle on zhtlc activation config cancel
smk762 Oct 28, 2025
0c2eef2
chore: roll SDK for streaming fix
CharlVS Oct 28, 2025
24276e8
chore: roll SDk
CharlVS Oct 28, 2025
6614fad
chore: roll SDK
CharlVS Oct 28, 2025
dce1709
fix: transaction history list sorting
CharlVS Oct 28, 2025
cf5c124
feat(wallet): realtime balance updates via CoinsBloc\n\n- Add balance…
CharlVS Oct 28, 2025
43a02dd
fix(wallet): preserve coin activation state on realtime balance updat…
CharlVS Oct 28, 2025
0f4bc96
refactor(withdraw): use absolute value of netchange in preview details
takenagain Oct 28, 2025
4ff4a6e
chore(fiat-onramp): add banxa iframe allow list
takenagain Oct 28, 2025
bb03bdc
Merge branch 'dev' into perf/3238-reduce-rpc-spam
CharlVS Oct 28, 2025
3f7703d
Merge branch 'dev' into perf/3238-reduce-rpc-spam
CharlVS Oct 29, 2025
00ab6c7
chore: roll sdk
CharlVS Oct 29, 2025
27b7db2
fix(wallet): isolate TransactionHistoryBloc per-coin to stop cross-as…
CharlVS Oct 29, 2025
7c79a2f
Merge branch 'dev' into fix-canceled-zhtlc-toggle
smk762 Oct 29, 2025
245d796
Merge branch 'dev' into fix-unban_pubkeys-null-check-error
smk762 Oct 29, 2025
8c8bb2b
Merge branch 'dev' into align-activation=state
smk762 Oct 29, 2025
b9ef42b
Merge branch 'dev' into hide-custom-seed-option
smk762 Oct 29, 2025
b51ee27
Merge pull request #3260 from KomodoPlatform/hide-custom-seed-option
ca333 Oct 29, 2025
e139c6b
Merge pull request #3206 from KomodoPlatform/feat/tendermint-faucet-c…
ca333 Oct 29, 2025
d25676d
Merge branch 'dev' into hotfix/fiat-form-and-banner
ca333 Oct 29, 2025
1742d1e
Merge pull request #3225 from KomodoPlatform/hotfix/fiat-form-and-banner
ca333 Oct 29, 2025
a54f065
Merge pull request #3272 from KomodoPlatform/align-activation=state
ca333 Oct 29, 2025
922a0d0
Merge pull request #3276 from KomodoPlatform/fix-unban_pubkeys-null-c…
ca333 Oct 29, 2025
c7e0a1e
Merge pull request #3274 from KomodoPlatform/fix/withdraw-form-values
ca333 Oct 29, 2025
1ade9f0
Merge pull request #3283 from KomodoPlatform/fix-canceled-zhtlc-toggle
ca333 Oct 29, 2025
1312486
Merge branch 'dev' into perf/3238-reduce-rpc-spam
ca333 Oct 29, 2025
6f9a5bb
Merge pull request #3253 from KomodoPlatform/perf/3238-reduce-rpc-spam
ca333 Oct 29, 2025
0a91838
add missing import refactor fiat_amount_input
ca333 Oct 29, 2025
2d82108
add unit tests
ca333 Oct 29, 2025
5252473
Merge branch 'dev' into fix_decimals
ca333 Oct 29, 2025
ebb3f74
Merge pull request #3297 from KomodoPlatform/fix_decimals
ca333 Oct 29, 2025
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
3 changes: 2 additions & 1 deletion assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@
"transactionDetailsTitle": "Transaction completed",
"customSeedWarningText": "Custom seed phrases are generally less secure and easier to crack than a generated BIP39-compliant seed phrase. To confirm you understand and are aware of the risk, type \"I understand\" in the box below.",
"customSeedIUnderstand": "i understand",
"walletCreationBip39SeedError": "BIP39 seed phrase validation failed, try again or select 'Allow custom seed'",

"walletCreationBip39SeedError": "BIP39 seed phrase validation failed, try again or select 'Use custom seed phrase / private key (WIF)' to proceed",
"walletCreationHdBip39SeedError": "Your input seed phrase is not BIP39 compliant, and can not be used in multi-address wallet mode. Please try again, or disable multi-address wallet mode and select 'Allow custom seed' to proceed.",
"walletPageNoSuchAsset": "No assets match search criteria",
"swap": "Swap",
Expand Down
22 changes: 11 additions & 11 deletions assets/web_pages/fiat_widget.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<body>
<iframe id="fiat-onramp-iframe" title="Fiat On-Ramp Widget"
sandbox="allow-forms allow-scripts allow-same-origin allow-popups allow-top-navigation allow-top-navigation-by-user-action"
src="">
allow="payment; encrypted-media; microphone; camera; midi" src="">
<!-- Placeholder fallback message -->
Comment on lines 30 to 32
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove allow-top-navigation; enforce iframe URL allowlist to prevent escape and phishing

  • The iframe’s sandbox currently includes allow-top-navigation, which enables top-level navigation from the provider; this contradicts the Dart settings comment and weakens isolation.
  • targetUrl is accepted from a base64 URL param without scheme/host validation. Add a strict allowlist to mitigate loading untrusted origins with camera/mic permissions.
-  <iframe id="fiat-onramp-iframe" title="Fiat On-Ramp Widget"
-    sandbox="allow-forms allow-scripts allow-same-origin allow-popups allow-top-navigation allow-top-navigation-by-user-action"
-    allow="payment; encrypted-media; microphone; camera; midi" src="">
+  <iframe id="fiat-onramp-iframe" title="Fiat On-Ramp Widget"
+    sandbox="allow-forms allow-scripts allow-same-origin allow-popups allow-top-navigation-by-user-activation"
+    allow="payment; encrypted-media; microphone; camera" src="">

Add strict URL validation before assigning iframe src:

 function _komodoSetIframeUrlFromParams() {
   const urlParam = _komodoGetUrlParameter('fiatUrl');
 
   let targetUrl = null;
   if (urlParam) {
     try {
       targetUrl = atob(urlParam); // base64 decode the `url` parameter
     } catch (error) {
       console.error('Error decoding base64 url parameter', error);
     }
   }
 
-  if (targetUrl) {
-    document.getElementById('fiat-onramp-iframe').src = targetUrl;
+  if (targetUrl) {
+    try {
+      const urlObj = new URL(targetUrl);
+      const allowedHosts = [
+        'app.ramp.network',
+        'app.demo.ramp.network',
+        'komodo.banxa.com',
+        'komodo.banxa-sandbox.com',
+        'embed.bitrefill.com',
+        'app.komodoplatform.com',
+      ];
+      const isHttp = urlObj.protocol === 'https:' || urlObj.protocol === 'http:';
+      const hostOk = allowedHosts.some(d => urlObj.hostname === d || urlObj.hostname.endsWith('.' + d));
+      if (!isHttp || !hostOk) {
+        throw new Error('Blocked untrusted iframe origin: ' + urlObj.hostname);
+      }
+      document.getElementById('fiat-onramp-iframe').src = urlObj.toString();
+    } catch (e) {
+      console.error('Invalid or disallowed targetUrl', e);
+    }
   } else {
     console.error('No URL parameter provided');
   }
 }

Optional hardening: restrict postMessage target origins instead of "*", if you can determine the parent’s origin.

Also applies to: 49-66

<p>Your browser does not support iframes.</p>
<p>Please use a modern browser to view this content.</p>
Expand Down Expand Up @@ -67,7 +67,7 @@

/**
* Get URL parameter by name
*
*
* @param {string} name - The name of the URL parameter to retrieve
* @returns {string|null} - The value of the URL parameter or null if not found
*/
Expand All @@ -76,10 +76,10 @@
return params.get(name);
}

/**
/**
* Handle messages from the iframe
*
* @param {MessageEvent} messageEvent
*
* @param {MessageEvent} messageEvent
*/
function _komodoOnMessageHandler(messageEvent) {
let messageData;
Expand All @@ -96,18 +96,18 @@
}
}

/**
/**
* Post a message to the parent window
*
* @param {string|object} messageData
*/
*
* @param {string|object} messageData
*/
function _komodoPostMessageToParent(messageData) {
const messageString = (typeof messageData === 'object') ? JSON.stringify(messageData) : String(messageData);

// flutter_inappwebview
console.log(messageString);

// universal_url opener
// universal_url opener
if (window.opener) {
return window.opener.postMessage(messageString, "*");
}
Expand All @@ -117,7 +117,7 @@
}

// Windows WebView2 (desktop_webview_window)
// https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/communicate-btwn-web-native
// https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/communicate-btwn-web-native
if (window.chrome && window.chrome.webview) {
return window.chrome.webview.postMessage(messageString);
}
Expand Down
6 changes: 3 additions & 3 deletions ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@
"$(PROJECT_DIR)",
);
MACOSX_DEPLOYMENT_TARGET = 15.0;
PRODUCT_BUNDLE_IDENTIFIER = com.komodoplatform.atomicdex;
PRODUCT_BUNDLE_IDENTIFIER = com.komodo.wallet;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify bundle identifier change impact and readiness.

Changing the iOS bundle identifier from com.komodoplatform.atomicdex to com.komodo.wallet creates a new app identity in Apple's ecosystem. This means existing users cannot update the app—they must install it as a new application, potentially losing data if migration is not handled.

Ensure the following are addressed:

  1. User data migration: Implement a strategy to migrate user data from the old app to the new one (e.g., using App Groups or iCloud storage).
  2. Apple Developer Portal updates: Update provisioning profiles, certificates, App Store Connect app record, push notifications, Sign in with Apple, associated domains, and any in-app purchases.
  3. Deep links and universal links: Update all configurations to use the new bundle identifier.
  4. Android consistency: Verify if a corresponding package name change was made for Android.
  5. Hardcoded references: Check for any hardcoded references to the old bundle identifier throughout the codebase.

Run the following script to check for hardcoded references to the old bundle identifier:

Also verify the Android package name for consistency:

Also applies to: 552-552, 587-587


🏁 Script executed:

#!/bin/bash
# Search for hardcoded references to the old bundle identifier

echo "Searching for old bundle identifier references..."
rg -n "com\.komodoplatform\.atomicdex" --type-add 'config:*.{plist,entitlements,xcconfig}' --type config

echo -e "\nSearching in Dart/Flutter files..."
rg -n "com\.komodoplatform\.atomicdex" --type dart

echo -e "\nSearching in Swift/Objective-C files..."
rg -n "com\.komodoplatform\.atomicdex" --type swift --type objc

echo -e "\nSearching in configuration files..."
rg -n "com\.komodoplatform\.atomicdex" --glob '*.json' --glob '*.yaml' --glob '*.yml'

Length of output: 280


🏁 Script executed:

#!/bin/bash
# Check Android package name in build.gradle

echo "Checking Android package name..."
fd -e gradle -x grep -Hn "applicationId"

Length of output: 115


🏁 Script executed:

#!/bin/bash
# Check for any references to the new iOS bundle ID in Android or Web files
echo "Checking if new iOS bundle ID appears in Android/Web configs..."
rg -n "com\.komodo\.wallet" --glob '*.gradle' --glob '*.json' --glob '*.yaml'

echo -e "\nLooking for package name patterns in Android files..."
rg -n "package" ./android/app/build.gradle -A2 -B2

echo -e "\nChecking Web manifest structure..."
cat ./web/manifest.json 2>/dev/null | head -20

Length of output: 221


🏁 Script executed:

#!/bin/bash
# Find and inspect Android and Web configuration files
echo "=== Finding Android build.gradle ==="
fd build.gradle -x cat {}

echo -e "\n=== Checking web/manifest.json ==="
fd manifest.json -x cat {}

echo -e "\n=== Checking if new iOS bundle ID (com.komodo.wallet) appears anywhere in non-iOS configs ==="
rg -n "com\.komodo\.wallet"

Length of output: 5338


Update Android and web configurations to match iOS bundle identifier change.

The iOS bundle identifier has been successfully changed to com.komodo.wallet across all configurations and code references. However, the Android and web configurations were not updated, creating a platform identity mismatch:

Required fixes:

  1. Android (android/app/build.gradle):

    • Line 42: Update namespace 'com.komodoplatform.atomicdex'namespace 'com.komodo.wallet'
    • Line 64: Update applicationId "com.komodoplatform.atomicdex"applicationId "com.komodo.wallet"
  2. Web (web/manifest.json line 15):

    • Update Play Store URL from com.komodoplatform.atomicdex to com.komodo.wallet

Additional concern: This is a breaking app identity change across platforms. Ensure a user data migration strategy exists (e.g., via App Groups, iCloud, or Firebase), and verify all infrastructure updates are ready (provisioning profiles, App Store Connect, certificates, Sign in with Apple, push notifications).

Also applies to: 552-552, 587-587

PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
Expand Down Expand Up @@ -549,7 +549,7 @@
"$(PROJECT_DIR)",
);
MACOSX_DEPLOYMENT_TARGET = 15.0;
PRODUCT_BUNDLE_IDENTIFIER = com.komodoplatform.atomicdex;
PRODUCT_BUNDLE_IDENTIFIER = com.komodo.wallet;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
Expand Down Expand Up @@ -584,7 +584,7 @@
"$(PROJECT_DIR)",
);
MACOSX_DEPLOYMENT_TARGET = 15.0;
PRODUCT_BUNDLE_IDENTIFIER = com.komodoplatform.atomicdex;
PRODUCT_BUNDLE_IDENTIFIER = com.komodo.wallet;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
Expand Down
3 changes: 1 addition & 2 deletions lib/app_config/app_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,9 @@ const List<String> appWalletOnlyAssetList = [
/// Reduced to only KMD to minimize initial connections and resource usage.
List<String> get enabledByDefaultCoins => [
'KMD', // Komodo ecosystem coin
'BTC-segwit' // Default Fiat Ramps coin
];

List<String> get coinsWithFaucet => ['RICK', 'MORTY', 'DOC', 'MARTY'];

const String logsDbName = 'logs';
const String appFolder = 'KomodoWallet';

Expand Down
5 changes: 0 additions & 5 deletions lib/bloc/app_bloc_root.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ import 'package:web_dex/bloc/system_health/system_health_bloc.dart';
import 'package:web_dex/bloc/taker_form/taker_bloc.dart';
import 'package:web_dex/bloc/trading_status/trading_status_bloc.dart';
import 'package:web_dex/bloc/trading_status/trading_status_service.dart';
import 'package:web_dex/bloc/transaction_history/transaction_history_bloc.dart';
import 'package:web_dex/bloc/transaction_history/transaction_history_repo.dart';
import 'package:web_dex/bloc/version_info/version_info_bloc.dart';
import 'package:web_dex/blocs/kmd_rewards_bloc.dart';
Expand Down Expand Up @@ -211,10 +210,6 @@ class AppBlocRoot extends StatelessWidget {
sdk: komodoDefiSdk,
),
),
BlocProvider<TransactionHistoryBloc>(
create: (BuildContext ctx) =>
TransactionHistoryBloc(sdk: komodoDefiSdk),
),
BlocProvider<SettingsBloc>(
create: (context) =>
SettingsBloc(storedPrefs, SettingsRepository()),
Expand Down
6 changes: 5 additions & 1 deletion lib/bloc/assets_overview/bloc/asset_overview_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:web_dex/bloc/cex_market_data/profit_loss/profit_loss_repository.
import 'package:web_dex/bloc/cex_market_data/sdk_auth_activation_extension.dart';
import 'package:web_dex/bloc/coins_bloc/asset_coin_extension.dart';
import 'package:web_dex/model/coin.dart';
import 'package:web_dex/shared/constants.dart';

part 'asset_overview_event.dart';
part 'asset_overview_state.dart';
Expand Down Expand Up @@ -100,7 +101,10 @@ class AssetOverviewBloc extends Bloc<AssetOverviewEvent, AssetOverviewState> {
return;
}

await _sdk.waitForEnabledCoinsToPassThreshold(supportedCoins);
await _sdk.waitForEnabledCoinsToPassThreshold(
supportedCoins,
delay: kActivationPollingInterval,
);

final activeCoins = await supportedCoins.removeInactiveCoins(_sdk);
if (activeCoins.isEmpty) {
Expand Down
117 changes: 61 additions & 56 deletions lib/bloc/bridge_form/bridge_validator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ class BridgeValidator {
required CoinsRepo coinsRepository,
required DexRepository dexRepository,
required KomodoDefiSdk sdk,
}) : _bloc = bloc,
_coinsRepo = coinsRepository,
_dexRepo = dexRepository,
_sdk = sdk,
_add = bloc.add;
}) : _bloc = bloc,
_coinsRepo = coinsRepository,
_dexRepo = dexRepository,
_sdk = sdk,
_add = bloc.add;

final BridgeBloc _bloc;
final CoinsRepo _coinsRepo;
Expand Down Expand Up @@ -71,32 +71,32 @@ class BridgeValidator {
}

DexFormError? _parsePreimageError(
DataFromService<TradePreimage, BaseError> preimageData) {
DataFromService<TradePreimage, BaseError> preimageData,
) {
final BaseError? error = preimageData.error;

if (error is TradePreimageNotSufficientBalanceError) {
return _insufficientBalanceError(
Rational.parse(error.required), error.coin);
Rational.parse(error.required),
error.coin,
);
} else if (error is TradePreimageNotSufficientBaseCoinBalanceError) {
return _insufficientBalanceError(
Rational.parse(error.required), error.coin);
} else if (error is TradePreimageTransportError) {
return DexFormError(
error: LocaleKeys.notEnoughBalanceForGasError.tr(),
Rational.parse(error.required),
error.coin,
);
} else if (error is TradePreimageTransportError) {
return DexFormError(error: LocaleKeys.notEnoughBalanceForGasError.tr());
} else if (error is TradePreimageVolumeTooLowError) {
return DexFormError(
error: LocaleKeys.lowTradeVolumeError
.tr(args: [formatAmt(double.parse(error.threshold)), error.coin]),
error: LocaleKeys.lowTradeVolumeError.tr(
args: [formatAmt(double.parse(error.threshold)), error.coin],
),
);
} else if (error != null) {
return DexFormError(
error: error.message,
);
return DexFormError(error: error.message);
} else if (preimageData.data == null) {
return DexFormError(
error: LocaleKeys.somethingWrong.tr(),
);
return DexFormError(error: LocaleKeys.somethingWrong.tr());
}

return null;
Expand Down Expand Up @@ -128,10 +128,15 @@ class BridgeValidator {
_state.sellAmount,
);
} catch (e, s) {
log(e.toString(),
trace: s, path: 'bridge_validator::_getPreimageData', isError: true);
log(
e.toString(),
trace: s,
path: 'bridge_validator::_getPreimageData',
isError: true,
);
return DataFromService(
error: TextError(error: 'Failed to request trade preimage'));
error: TextError(error: 'Failed to request trade preimage'),
);
}
Comment on lines +131 to 140
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Localize and preserve context in preimage fetch failure.

Error text is hard-coded and loses localization. Also include a concise reason for better UX.

-      return DataFromService(
-        error: TextError(error: 'Failed to request trade preimage'),
-      );
+      return DataFromService(
+        error: TextError(
+          error: LocaleKeys.somethingWrong.tr(), // generic localized fallback
+        ),
+      );

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In lib/bloc/bridge_form/bridge_validator.dart around lines 131–140, replace the
hard-coded error TextError('Failed to request trade preimage') with a localized
message pulled from the app's localization resources and include a concise
reason derived from the caught exception (e.g., a short e.message or first 100
chars of e.toString()) so users see context; keep the existing log call
unchanged but ensure the DataFromService.error uses something like
Localizations.instance['failed_fetch_preimage'] (or your project's
S/AppLocalizations helper) and append the concise reason (safely truncated to
avoid leaking sensitive data).

}

Expand Down Expand Up @@ -187,17 +192,17 @@ class BridgeValidator {
if (availableBalance < maxOrderVolume && sellAmount > availableBalance) {
final Rational minAmount = maxRational([
_state.minSellAmount ?? Rational.zero,
_state.bestOrder!.minVolume
_state.bestOrder!.minVolume,
])!;

if (availableBalance < minAmount) {
_add(BridgeSetError(
_insufficientBalanceError(minAmount, _state.sellCoin!.abbr),
));
_add(
BridgeSetError(
_insufficientBalanceError(minAmount, _state.sellCoin!.abbr),
),
);
} else {
_add(BridgeSetError(
_setMaxError(availableBalance),
));
_add(BridgeSetError(_setMaxError(availableBalance)));
}

return false;
Expand All @@ -218,9 +223,11 @@ class BridgeValidator {
if (sellAmount < minAmount) {
final Rational available = _state.maxSellAmount ?? Rational.zero;
if (available < minAmount) {
_add(BridgeSetError(
_insufficientBalanceError(minAmount, _state.sellCoin!.abbr),
));
_add(
BridgeSetError(
_insufficientBalanceError(minAmount, _state.sellCoin!.abbr),
),
);
} else {
_add(BridgeSetError(_setMinError(minAmount)));
}
Expand All @@ -233,22 +240,17 @@ class BridgeValidator {

Future<bool> _validateCoinAndParent(String abbr) async {
final coin = _sdk.getSdkAsset(abbr);
final enabledAssets = await _sdk.assets.getActivatedAssets();
final isAssetEnabled = enabledAssets.contains(coin);
final activatedAssetIds = await _coinsRepo.getActivatedAssetIds();
final parentId = coin.id.parentId;
final parent = _sdk.assets.available[parentId];

if (!isAssetEnabled) {
if (!activatedAssetIds.contains(coin.id)) {
_add(BridgeSetError(_coinNotActiveError(coin.id.id)));
return false;
}

if (parent != null) {
final isParentEnabled = enabledAssets.contains(parent);
if (!isParentEnabled) {
_add(BridgeSetError(_coinNotActiveError(parent.id.id)));
return false;
}
if (parentId != null && !activatedAssetIds.contains(parentId)) {
_add(BridgeSetError(_coinNotActiveError(parentId.id)));
return false;
}

return true;
Expand All @@ -262,7 +264,8 @@ class BridgeValidator {

final selectedOrderAddress = selectedOrder.address;
final asset = _sdk.getSdkAsset(selectedOrder.coin);
final ownPubkeys = await _sdk.pubkeys.getPubkeys(asset);
final cached = _sdk.pubkeys.lastKnown(asset.id);
final ownPubkeys = cached ?? await _sdk.pubkeys.getPubkeys(asset);
final ownAddresses = ownPubkeys.keys
Comment on lines +267 to 269
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Harden trading-with-self check against pubkeys fetch failures.

A transient pubkeys error will currently abort validation. Catch and degrade to “not trading with self” while logging.

-    final cached = _sdk.pubkeys.lastKnown(asset.id);
-    final ownPubkeys = cached ?? await _sdk.pubkeys.getPubkeys(asset);
+    final cached = _sdk.pubkeys.lastKnown(asset.id);
+    AssetPubkeys? ownPubkeys = cached;
+    if (ownPubkeys == null) {
+      try {
+        ownPubkeys = await _sdk.pubkeys.getPubkeys(asset);
+      } catch (e, s) {
+        log(
+          'Failed to load pubkeys for self-trade check: $e',
+          trace: s,
+          path: 'bridge_validator::_checkTradeWithSelf',
+          isError: true,
+        );
+        return false; // Don’t block the user on this non-critical check
+      }
+    }
🤖 Prompt for AI Agents
In lib/bloc/bridge_form/bridge_validator.dart around lines 267 to 269, the call
to await _sdk.pubkeys.getPubkeys(asset) can throw and currently aborts
validation; wrap the fetch in a try/catch, on success use the returned map as
ownPubkeys, on failure log the error (using the file's existing logger) and
assign an empty map for ownPubkeys so ownAddresses becomes empty (which degrades
to “not trading with self”); keep using cached when available and preserve
existing control flow otherwise.

.where((pubkeyInfo) => pubkeyInfo.isActiveForSwap)
.map((e) => e.address)
Expand Down Expand Up @@ -304,8 +307,9 @@ class BridgeValidator {

DexFormError _setOrderMaxError(Rational maxAmount) {
return DexFormError(
error: LocaleKeys.dexMaxOrderVolume
.tr(args: [formatDexAmt(maxAmount), _state.sellCoin!.abbr]),
error: LocaleKeys.dexMaxOrderVolume.tr(
args: [formatDexAmt(maxAmount), _state.sellCoin!.abbr],
),
type: DexFormErrorType.largerMaxSellVolume,
action: DexFormErrorAction(
text: LocaleKeys.setMax.tr(),
Expand All @@ -318,8 +322,9 @@ class BridgeValidator {

DexFormError _insufficientBalanceError(Rational required, String abbr) {
return DexFormError(
error: LocaleKeys.dexBalanceNotSufficientError
.tr(args: [abbr, formatDexAmt(required), abbr]),
error: LocaleKeys.dexBalanceNotSufficientError.tr(
args: [abbr, formatDexAmt(required), abbr],
),
);
}

Expand All @@ -341,20 +346,20 @@ class BridgeValidator {
DexFormError _setMinError(Rational minAmount) {
return DexFormError(
type: DexFormErrorType.lessMinVolume,
error: LocaleKeys.dexMinSellAmountError
.tr(args: [formatDexAmt(minAmount), _state.sellCoin!.abbr]),
error: LocaleKeys.dexMinSellAmountError.tr(
args: [formatDexAmt(minAmount), _state.sellCoin!.abbr],
),
action: DexFormErrorAction(
text: LocaleKeys.setMin.tr(),
callback: () async {
_add(BridgeSetSellAmount(minAmount));
}),
text: LocaleKeys.setMin.tr(),
callback: () async {
_add(BridgeSetSellAmount(minAmount));
},
),
);
}

DexFormError _tradingWithSelfError() {
return DexFormError(
error: LocaleKeys.dexTradingWithSelfError.tr(),
);
return DexFormError(error: LocaleKeys.dexTradingWithSelfError.tr());
}

bool get _isSellCoinSelected => _state.sellCoin != null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:web_dex/bloc/coins_bloc/asset_coin_extension.dart';
import 'package:web_dex/mm2/mm2_api/rpc/base.dart';
import 'package:web_dex/model/coin.dart';
import 'package:web_dex/model/text_error.dart';
import 'package:web_dex/shared/constants.dart';

part 'portfolio_growth_event.dart';
part 'portfolio_growth_state.dart';
Expand Down Expand Up @@ -160,7 +161,10 @@ class PortfolioGrowthBloc
// In case most coins are activating on wallet startup, wait for at least
// 50% of the coins to be enabled before attempting to load the uncached
// chart.
await _sdk.waitForEnabledCoinsToPassThreshold(filteredEventCoins);
await _sdk.waitForEnabledCoinsToPassThreshold(
filteredEventCoins,
delay: kActivationPollingInterval,
);

// Only remove inactivate/activating coins after an attempt to load the
// cached chart, as the cached chart may contain inactive coins.
Expand Down
Loading
Loading