Skip to content
Merged
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
73 changes: 73 additions & 0 deletions packages/komodo_defi_framework/lib/komodo_defi_framework.dart
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ class KomodoDefiFramework implements ApiClient {
final method = request['method'] as String?;
final stopwatch = Stopwatch()..start();

// Log activation parameters before the call
if (method != null && _isActivationMethod(method)) {
_logActivationParameters(method, request);
}

try {
final response = (await _kdfOperations.mm2Rpc(
request..setIfAbsentOrEmpty('userpass', _hostConfig.rpcPassword),
Expand Down Expand Up @@ -258,6 +263,74 @@ class KomodoDefiFramework implements ApiClient {
method == 'my_balance';
}

bool _isActivationMethod(String method) {
return method.contains('enable') ||
method.contains('task::enable') ||
method.contains('task_enable');
}

void _logActivationParameters(String method, JsonMap request) {
try {
final params = request['params'] as Map<String, dynamic>?;
if (params == null) return;

final ticker = params['ticker'] as String?;
final activationParams = params['activation_params'] as Map<String, dynamic>?;

if (ticker != null) {
_logger.info('[ACTIVATION] Enabling coin: $ticker');
}

if (activationParams != null) {
// Log key activation parameters
final mode = activationParams['mode'];
final nodes = activationParams['nodes'];
final servers = activationParams['servers'];
final rpcUrls = activationParams['rpc_urls'];
final tokensRequests = activationParams['erc20_tokens_requests'];
final bchUrls = activationParams['bchd_urls'];

final paramsSummary = <String, dynamic>{};

if (mode != null) paramsSummary['mode'] = mode;
if (nodes != null) {
paramsSummary['nodes_count'] = (nodes as List).length;
}
if (servers != null) {
paramsSummary['electrum_servers_count'] = (servers as List).length;
}
if (rpcUrls != null) {
paramsSummary['rpc_urls_count'] = (rpcUrls as List).length;
}
if (tokensRequests != null) {
paramsSummary['tokens_count'] = (tokensRequests as List).length;
}
if (bchUrls != null) {
paramsSummary['bchd_urls_count'] = (bchUrls as List).length;
}

// Add other relevant fields
if (activationParams['swap_contract_address'] != null) {
paramsSummary['swap_contract'] = activationParams['swap_contract_address'];
}
if (activationParams['platform'] != null) {
paramsSummary['platform'] = activationParams['platform'];
}
if (activationParams['contract_address'] != null) {
paramsSummary['contract_address'] = activationParams['contract_address'];
}

_logger.info('[ACTIVATION] Parameters: $paramsSummary');

// Log full activation params for detailed debugging
_logger.fine('[ACTIVATION] Full params: $activationParams');
}
} catch (e) {
// Silently ignore logging errors
_logger.info('[ACTIVATION] Error logging parameters: $e');
Copy link

Copilot AI Oct 26, 2025

Choose a reason for hiding this comment

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

Error logging uses info level instead of warning or error level. Change to _logger.warning('[ACTIVATION] Error logging parameters: $e'); to properly indicate this is an error condition.

Suggested change
_logger.info('[ACTIVATION] Error logging parameters: $e');
_logger.warning('[ACTIVATION] Error logging parameters: $e');

Copilot uses AI. Check for mistakes.
}
}

void _logElectrumConnectionInfo(String method, JsonMap response) {
try {
// Log connection information from enable responses
Expand Down
73 changes: 73 additions & 0 deletions packages/komodo_defi_framework/lib/src/client/kdf_api_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ class KdfApiClient implements ApiClient {
final method = request['method'] as String?;
final stopwatch = Stopwatch()..start();

// Log activation parameters before the call
if (method != null && _isActivationMethod(method)) {
_logActivationParameters(method, request);
}

try {
final response = _rpcCallback(request);
stopwatch.stop();
Expand Down Expand Up @@ -68,6 +73,74 @@ class KdfApiClient implements ApiClient {
method == 'my_balance';
}

bool _isActivationMethod(String method) {
return method.contains('enable') ||
method.contains('task::enable') ||
method.contains('task_enable');
}

void _logActivationParameters(String method, JsonMap request) {
try {
final params = request['params'] as Map<String, dynamic>?;
if (params == null) return;

final ticker = params['ticker'] as String?;
final activationParams = params['activation_params'] as Map<String, dynamic>?;

if (ticker != null) {
_logger.info('[ACTIVATION] Enabling coin: $ticker');
}

if (activationParams != null) {
// Log key activation parameters
final mode = activationParams['mode'];
final nodes = activationParams['nodes'];
final servers = activationParams['servers'];
final rpcUrls = activationParams['rpc_urls'];
final tokensRequests = activationParams['erc20_tokens_requests'];
final bchUrls = activationParams['bchd_urls'];

final paramsSummary = <String, dynamic>{};

if (mode != null) paramsSummary['mode'] = mode;
if (nodes != null) {
paramsSummary['nodes_count'] = (nodes as List).length;
}
if (servers != null) {
paramsSummary['electrum_servers_count'] = (servers as List).length;
}
if (rpcUrls != null) {
paramsSummary['rpc_urls_count'] = (rpcUrls as List).length;
}
if (tokensRequests != null) {
paramsSummary['tokens_count'] = (tokensRequests as List).length;
}
if (bchUrls != null) {
paramsSummary['bchd_urls_count'] = (bchUrls as List).length;
}

// Add other relevant fields
if (activationParams['swap_contract_address'] != null) {
paramsSummary['swap_contract'] = activationParams['swap_contract_address'];
}
if (activationParams['platform'] != null) {
paramsSummary['platform'] = activationParams['platform'];
}
if (activationParams['contract_address'] != null) {
paramsSummary['contract_address'] = activationParams['contract_address'];
}

_logger.info('[ACTIVATION] Parameters: $paramsSummary');

// Log full activation params for detailed debugging
_logger.fine('[ACTIVATION] Full params: $activationParams');
}
} catch (e) {
// Silently ignore logging errors
_logger.fine('[ACTIVATION] Error logging parameters: $e');
Copy link

Copilot AI Oct 26, 2025

Choose a reason for hiding this comment

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

Error logging uses fine level instead of warning or error level. Change to _logger.warning('[ACTIVATION] Error logging parameters: $e'); to properly indicate this is an error condition.

Suggested change
_logger.fine('[ACTIVATION] Error logging parameters: $e');
_logger.warning('[ACTIVATION] Error logging parameters: $e');

Copilot uses AI. Check for mistakes.
}
}

void _logElectrumConnectionInfo(String method, JsonMap response) {
try {
// Log connection information from enable responses
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ class _FakeAuthService implements IAuthService {
bool signOutCalled = false;
({String walletName, String password, AuthOptions options})? lastSignInArgs;
({String walletName, String password, AuthOptions options})? lastRegisterArgs;
bool ensureHealthyReturn = true;
int ensureHealthyCalls = 0;

@override
Stream<KdfUser?> get authStateChanges => _authStateController.stream;
Expand Down Expand Up @@ -198,6 +200,12 @@ class _FakeAuthService implements IAuthService {
required String currentPassword,
required String newPassword,
}) async => throw UnimplementedError();

@override
Future<bool> ensureKdfHealthy() async {
ensureHealthyCalls++;
return ensureHealthyReturn;
}
}

void main() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,20 @@ enum ScanPolicy {
/// Contains information about electrum & lightwallet_d servers for coins being used
/// in 'Electrum' or 'Light' mode
class ActivationRpcData {
ActivationRpcData({this.lightWalletDServers, this.electrum, this.syncParams});
ActivationRpcData({
this.lightWalletDServers,
this.electrum,
this.syncParams,
this.minConnected,
this.maxConnected = 1,
}) : assert(
minConnected == null || minConnected >= 1,
'min_connected must be at least 1',
),
assert(
minConnected == null || (maxConnected ?? 1) >= minConnected,
'min_connected cannot exceed max_connected',
);

/// Creates [ActivationRpcData] from JSON configuration
factory ActivationRpcData.fromJson(JsonMap json) {
Expand All @@ -381,6 +394,8 @@ class ActivationRpcData {
syncParams: ZhtlcSyncParams.tryParse(
json.valueOrNull<dynamic>('sync_params'),
),
minConnected: json.valueOrNull<int>('min_connected'),
maxConnected: json.valueOrNull<int>('max_connected'),
);
}

Expand All @@ -390,6 +405,12 @@ class ActivationRpcData {
/// List of electrum servers for QTUM, BCH & UTXO coins
final List<ActivationServers>? electrum;

/// Minimum number of electrum servers to keep connected. Optional.
final int? minConnected;

/// Maximum number of electrum servers to keep connected. Defaults to 1.
final int? maxConnected;

/// ZHTLC coins only. Optional, defaults to two days ago. Defines where to start
/// scanning blockchain data upon initial activation.
///
Expand All @@ -411,6 +432,8 @@ class ActivationRpcData {
(forLightWallet ? 'electrum_servers' : 'servers'): electrum!
.map((e) => e.toJsonRequest())
.toList(),
if (electrum != null) 'max_connected': (maxConnected ?? 1),
Copy link

Copilot AI Oct 26, 2025

Choose a reason for hiding this comment

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

The max_connected parameter is being included whenever electrum is not null, but it should only be included when explicitly set. This could send default values even when not intended. Change condition to if (maxConnected != null) to only include when explicitly provided.

Suggested change
if (electrum != null) 'max_connected': (maxConnected ?? 1),
if (maxConnected != null) 'max_connected': maxConnected,

Copilot uses AI. Check for mistakes.
if (minConnected != null) 'min_connected': minConnected,
if (syncParams != null) 'sync_params': syncParams!.toJsonRequest(),
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import 'dart:convert';
import 'dart:developer' show log;

import 'package:komodo_defi_rpc_methods/komodo_defi_rpc_methods.dart';
import 'package:komodo_defi_sdk/src/activation/_activation.dart';
import 'package:komodo_defi_types/komodo_defi_types.dart';
Expand Down Expand Up @@ -82,16 +85,39 @@ class BchActivationStrategy extends ProtocolActivationStrategy {
),
);

final slpTokensRequests = children
?.map(
(child) => TokensRequest(ticker: child.id.id),
)
.toList() ??
[];

// Debug logging for BCH activation
log(
'[RPC] Activating BCH platform: ${asset.id.id}',
name: 'BchActivationStrategy',
);
log(
'[RPC] Activation parameters: ${jsonEncode({
'ticker': asset.id.id,
'protocol': asset.protocol.subClass.formatted,
'slp_token_count': children?.length ?? 0,
'slp_tokens': children?.map((e) => e.id.id).toList() ?? [],
'activation_params': bchConfig.toRpcParams(),
})}',
name: 'BchActivationStrategy',
);

// Enable BCH with SLP support
final response = await client.rpc.slp.enableBchWithTokens(
ticker: asset.id.id,
params: bchConfig,
slpTokensRequests: children
?.map(
(child) => TokensRequest(ticker: child.id.id),
)
.toList() ??
[],
slpTokensRequests: slpTokensRequests,
);

log(
'[RPC] Successfully activated BCH with ${children?.length ?? 0} SLP tokens',
name: 'BchActivationStrategy',
);

yield ActivationProgress(
Expand Down Expand Up @@ -129,10 +155,29 @@ class BchActivationStrategy extends ProtocolActivationStrategy {
),
);

// Debug logging for SLP token activation
log(
'[RPC] Activating SLP token: ${asset.id.id}',
name: 'BchActivationStrategy',
);
log(
'[RPC] Activation parameters: ${jsonEncode({
'ticker': asset.id.id,
'protocol': asset.protocol.subClass.formatted,
'parent_id': asset.id.parentId?.id,
})}',
name: 'BchActivationStrategy',
);

await client.rpc.slp.enableSlpToken(
ticker: asset.id.id,
params: SlpActivationParams(),
);

log(
'[RPC] Successfully activated SLP token: ${asset.id.id}',
name: 'BchActivationStrategy',
);

yield ActivationProgress.success(
details: ActivationProgressDetails(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import 'dart:convert';
import 'dart:developer' show log;

import 'package:komodo_defi_rpc_methods/komodo_defi_rpc_methods.dart';
import 'package:komodo_defi_sdk/src/activation/_activation.dart';
import 'package:komodo_defi_types/komodo_defi_type_utils.dart';
Expand Down Expand Up @@ -60,13 +63,38 @@ class CustomErc20ActivationStrategy extends ProtocolActivationStrategy {
throw StateError('Protocol data is missing from custom token config');
}

final activationParams = Erc20ActivationParams.fromJsonConfig(
asset.protocol.config,
);
final platform = protocolData.value<String>('platform');
final contractAddress = protocolData.value<String>('contract_address');

// Debug logging for custom ERC20 token activation
log(
'[RPC] Activating custom ERC20 token: ${asset.id.id}',
name: 'CustomErc20ActivationStrategy',
);
log(
'[RPC] Activation parameters: ${jsonEncode({
'ticker': asset.id.id,
'protocol': asset.protocol.subClass.formatted,
'platform': platform,
'contract_address': contractAddress,
'activation_params': activationParams.toRpcParams(),
})}',
name: 'CustomErc20ActivationStrategy',
);

await client.rpc.erc20.enableCustomErc20Token(
ticker: asset.id.id,
activationParams: Erc20ActivationParams.fromJsonConfig(
asset.protocol.config,
),
platform: protocolData.value<String>('platform'),
contractAddress: protocolData.value<String>('contract_address'),
activationParams: activationParams,
platform: platform,
contractAddress: contractAddress,
);

log(
'[RPC] Successfully activated custom ERC20 token: ${asset.id.id}',
name: 'CustomErc20ActivationStrategy',
);

yield ActivationProgress.success(
Expand Down
Loading
Loading