Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
6ff31f3
fix(screenshot-sensitivity): notify listeners in postFrameCallback
takenagain Sep 24, 2025
212ad6d
chore(sdk): switch to zhtlc branch
takenagain Sep 25, 2025
23ded71
feat(zhtlc): add configuration and param download dialogs
takenagain Sep 26, 2025
349baca
refactor: generate localisations, and fix theming on popup dialog
takenagain Sep 26, 2025
d33742e
refactor: use repositoryprovider and adjust status bar width
takenagain Sep 26, 2025
79ee69d
Merge remote-tracking branch 'origin/dev' into feat/zhtlc-asset-support
takenagain Sep 26, 2025
521ba35
perf(coins-manager): add input debouncer and cache heavy operations
takenagain Sep 26, 2025
9c68937
fix(activation): swap page activation, improve list and disposal mana…
takenagain Sep 27, 2025
16c5e5a
fix(zhtlc): update activation warning, add padding, and stealth text
takenagain Sep 27, 2025
b351e11
feat(orderbook): migrate to v2 orderbook RPC via SDK
takenagain Sep 28, 2025
3a6d3db
perf(dex): remove enabled assets rpc call from taker validator
takenagain Sep 28, 2025
2f0a129
style(zhtlc): improve dialog layout, add transaction note, fix hidden…
takenagain Sep 28, 2025
a264209
fix(market-metrics): filter out inactive coins before starting calcs
takenagain Sep 29, 2025
ccfae68
fix(zhtlc): workaround "Task is finished" error with retry on activation
takenagain Sep 29, 2025
6968034
feat(zhtlc): add activation status to banner
takenagain Sep 30, 2025
0c34a9b
fix(withdraw): add recipient address and memo (if not empty)
takenagain Sep 30, 2025
0e0fd64
fix(zhtlc): filter out active assets before attempting zhtlc activation
takenagain Sep 30, 2025
b85c889
fix(wallet): add resilience to delisted coins for wallet coin metadata
takenagain Sep 30, 2025
a130697
fix(version-info): ensure that apiversion and commit has persist
takenagain Sep 30, 2025
3537231
perf(market-data): add update backoff strategy and guard against fetc…
takenagain Oct 1, 2025
3b4319b
Merge branch 'dev' into feat/zhtlc-asset-support
takenagain Oct 1, 2025
a82e022
perf(dex): reduce overhead in coin selection and filtering
takenagain Oct 1, 2025
ccfae6a
fix(dex): only update sell amount on order selection if no value present
takenagain Oct 1, 2025
fd73814
Merge branch 'dev' into feat/zhtlc-asset-support
takenagain Oct 1, 2025
1e58d91
fix(zhtlc): track ongoing activations to prevent duplicate requests
takenagain Oct 1, 2025
066dd1d
fix(taker-validator): revert to getting active assets from API
takenagain Oct 2, 2025
99602ee
Merge remote-tracking branch 'origin/dev' into feat/zhtlc-asset-support
takenagain Oct 2, 2025
4416b1c
chore(sdk): switch back to dev branch (sdk branch merged)
takenagain Oct 2, 2025
c6e7621
Merge remote-tracking branch 'origin/dev' into feat/zhtlc-asset-support
takenagain Oct 2, 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
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[submodule "sdk"]
path = sdk
url = https://github.com/KomodoPlatform/komodo-defi-sdk-flutter.git
branch = dev
branch = bugfix/zhltc-activation-fixes
update = checkout
fetchRecurseSubmodules = on-demand
ignore = dirty
24 changes: 22 additions & 2 deletions assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,6 @@
"backupSeedPhrase": "Backup seed phrase",
"seedOr": "OR",
"seedDownload": "Download seed phrase",
"seedSaveAndRemember": "Save and remember",
"seedIntroWarning": "This phrase is the main access to your\nassets, save and never share this phrase",
"seedSettings": "Seed phrase",
"errorDescription": "Error description",
Expand Down Expand Up @@ -761,5 +760,26 @@
"fetchingPrivateKeysTitle": "Fetching Private Keys...",
"fetchingPrivateKeysMessage": "Please wait while we securely fetch your private keys...",
"pubkeyType": "Type",
"securitySettings": "Security Settings"
"securitySettings": "Security Settings",
"zhtlcConfigureTitle": "Configure {}",
"zhtlcZcashParamsPathLabel": "Zcash parameters path",
"zhtlcPathAutomaticallyDetected": "Path automatically detected",
"zhtlcSaplingParamsFolder": "Folder containing sapling params",
"zhtlcBlocksPerIterationLabel": "Blocks per iteration",
"zhtlcScanIntervalLabel": "Scan interval (ms)",
"zhtlcStartSyncFromLabel": "Start sync from:",
"zhtlcEarliestSaplingOption": "Earliest (sapling)",
"zhtlcBlockHeightOption": "Block height",
"zhtlcDateTimeOption": "Date & Time",
"zhtlcSelectDateTimeLabel": "Select date & time",
"zhtlcZcashParamsRequired": "Zcash params path is required",
"zhtlcInvalidBlockHeight": "Enter a valid block height",
"zhtlcSelectDateTimeRequired": "Please select a date and time",
"zhtlcDownloadingZcashParams": "Downloading Zcash Parameters",
"zhtlcPreparingDownload": "Preparing download...",
"zhtlcErrorSettingUpZcash": "Error setting up Zcash parameters: {}",
"activatingZhtlcCoins": {
"one": "Activating ZHTLC coin: {}",
"other": "Activating ZHTLC coins: {}"
}
}
7 changes: 0 additions & 7 deletions lib/app_config/app_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,8 @@ const Set<String> excludedAssetList = {
'FENIX',
'AWR',
'BOT',
// Pirate activation params are not yet implemented, so we need to
// exclude it from the list of coins for now.
'ARRR',
'ZOMBIE',
'SMTF-v2',
'SFUSD',
'VOTE2023',
'RICK',
'MORTY',

// NFT v2 coins: https://github.com/KomodoPlatform/coins/pull/1061 will be
// used in the background, so users do not need to see them.
Expand Down
1 change: 1 addition & 0 deletions lib/bloc/app_bloc_root.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import 'package:web_dex/bloc/bridge_form/bridge_repository.dart';
import 'package:web_dex/bloc/cex_market_data/mockup/generator.dart';
import 'package:web_dex/bloc/cex_market_data/mockup/mock_transaction_history_repository.dart';
import 'package:web_dex/bloc/cex_market_data/mockup/performance_mode.dart';
import 'package:web_dex/services/arrr_activation/arrr_activation_service.dart';
import 'package:web_dex/bloc/cex_market_data/portfolio_growth/portfolio_growth_bloc.dart';
import 'package:web_dex/bloc/cex_market_data/portfolio_growth/portfolio_growth_repository.dart';
import 'package:web_dex/bloc/cex_market_data/price_chart/price_chart_bloc.dart';
Expand Down
135 changes: 132 additions & 3 deletions lib/bloc/coins_bloc/coins_repo.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:math' show min;
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart' show NetworkImage;
import 'package:get_it/get_it.dart';
import 'package:komodo_defi_rpc_methods/komodo_defi_rpc_methods.dart'
as kdf_rpc;
import 'package:komodo_defi_sdk/komodo_defi_sdk.dart';
Expand All @@ -27,6 +28,7 @@ import 'package:web_dex/model/kdf_auth_metadata_extension.dart';
import 'package:web_dex/model/text_error.dart';
import 'package:web_dex/model/wallet.dart';
import 'package:web_dex/model/withdraw_details/withdraw_details.dart';
import 'package:web_dex/services/arrr_activation/arrr_activation_service.dart';

class CoinsRepo {
CoinsRepo({required KomodoDefiSdk kdfSdk, required MM2 mm2})
Expand Down Expand Up @@ -82,7 +84,7 @@ class CoinsRepo {
BalanceInfo? lastKnownBalance(AssetId id) => _kdfSdk.balances.lastKnown(id);

/// Subscribe to balance updates for an asset using the SDK's balance manager
void _subscribeToBalanceUpdates(Asset asset, Coin coin) {
void _subscribeToBalanceUpdates(Asset asset) {
// Cancel any existing subscription for this asset
_balanceWatchers[asset.id]?.cancel();

Expand Down Expand Up @@ -280,6 +282,15 @@ class CoinsRepo {
return;
}

if (assets.any((asset) => asset.id.subClass == CoinSubClass.zhtlc)) {
return _activateZhtlcAssets(
assets,
assets.map((asset) => _assetToCoinWithoutAddress(asset)).toList(),
notifyListeners: notifyListeners,
addToWalletMetadata: addToWalletMetadata,
);
}
Comment thread
takenagain marked this conversation as resolved.
Outdated

if (addToWalletMetadata) {
// Ensure the wallet metadata is updated with the assets before activation
// This is to ensure that the wallet metadata is always in sync with the assets
Expand Down Expand Up @@ -333,13 +344,13 @@ class CoinsRepo {
_broadcastAsset(parentCoin.copyWith(state: CoinState.active));
}
}
_subscribeToBalanceUpdates(asset, coin);
_subscribeToBalanceUpdates(asset);
if (coin.id.parentId != null) {
final parentAsset = _kdfSdk.assets.available[coin.id.parentId];
if (parentAsset == null) {
_log.warning('Parent asset not found: ${coin.id.parentId}');
} else {
_subscribeToBalanceUpdates(parentAsset, coin);
_subscribeToBalanceUpdates(parentAsset);
}
}
} catch (e, s) {
Expand Down Expand Up @@ -702,4 +713,122 @@ class CoinsRepo {

return BlocResponse(result: withdrawDetails);
}

Future<void> _activateZhtlcAssets(
List<Asset> assets,
List<Coin> coins, {
bool notifyListeners = true,
bool addToWalletMetadata = true,
}) async {
for (final asset in assets) {
final coin = coins.firstWhere((coin) => coin.id == asset.id);
await _activateZhtlcAsset(
asset,
coin,
notifyListeners: notifyListeners,
addToWalletMetadata: addToWalletMetadata,
);
}
}

/// Activates a ZHTLC asset using ArrrActivationService
/// This will wait for user configuration if needed before proceeding with activation
/// Mirrors the notify and addToWalletMetadata functionality of activateAssetsSync
Future<void> _activateZhtlcAsset(
Asset asset,
Coin coin, {
bool notifyListeners = true,
bool addToWalletMetadata = true,
}) async {
try {
final arrrActivationService = GetIt.I<ArrrActivationService>();

_log.info('Starting ZHTLC activation for ${asset.id.id}');

// Use the service's future-based activation which will handle configuration
// The service will emit to its stream for UI to handle, and this future will
// complete only after configuration is provided and activation succeeds.
// This ensures CoinsRepo waits for user inputs for config params from the dialog
// before proceeding with activation, and doesn't broadcast activation status
// until config parameters are received and (desktop) params files downloaded.
final result = await arrrActivationService.activateArrr(asset);

result.when(
success: (progress) async {
_log.info('ZHTLC asset activated successfully: ${asset.id.id}');

if (addToWalletMetadata) {
await _addAssetsToWalletMetdata([asset.id]);
}

if (notifyListeners) {
_broadcastAsset(coin.copyWith(state: CoinState.activating));
}

if (notifyListeners) {
_broadcastAsset(coin.copyWith(state: CoinState.active));
if (coin.id.parentId != null) {
final parentCoin = _assetToCoinWithoutAddress(
_kdfSdk.assets.available[coin.id.parentId]!,
);
_broadcastAsset(parentCoin.copyWith(state: CoinState.active));
}
}

_subscribeToBalanceUpdates(asset);
if (coin.id.parentId != null) {
final parentAsset = _kdfSdk.assets.available[coin.id.parentId];
if (parentAsset == null) {
_log.warning('Parent asset not found: ${coin.id.parentId}');
} else {
_subscribeToBalanceUpdates(parentAsset);
}
}

if (coin.logoImageUrl?.isNotEmpty ?? false) {
AssetIcon.registerCustomIcon(
coin.id,
NetworkImage(coin.logoImageUrl!),
);
}
},
error: (message) {
_log.severe(
'ZHTLC asset activation failed: ${asset.id.id} - $message',
);

if (notifyListeners) {
_broadcastAsset(coin.copyWith(state: CoinState.suspended));
}

throw Exception('ZHTLC activation failed: $message');
},
needsConfiguration: (coinId, requiredSettings) {
_log.severe(
Comment thread
takenagain marked this conversation as resolved.
'ZHTLC activation should not return needsConfiguration in future-based call',
);
_log.severe(
'Unexpected needsConfiguration result for ${asset.id.id}',
);

if (notifyListeners) {
_broadcastAsset(coin.copyWith(state: CoinState.suspended));
}

throw Exception(
'ZHTLC activation configuration not handled properly',
);
},
);
} catch (e, s) {
_log.severe('Error activating ZHTLC asset ${asset.id.id}', e, s);

// Broadcast suspended state if requested
if (notifyListeners) {
_broadcastAsset(coin.copyWith(state: CoinState.suspended));
}

rethrow;
}
}
}
Loading