"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateCoinExists = exports.validateOrderParams = exports.getMaxOrderValue = exports.getSupportedPaths = exports.applyPathFilters = exports.validateBalance = exports.validateAssetSupport = exports.validateDepositParams = exports.validateWithdrawalParams = exports.createErrorResult = void 0;
const utils_1 = require("@metamask/utils");
const hyperLiquidConfig_1 = require("../constants/hyperLiquidConfig.cjs");
const perpsConfig_1 = require("../constants/perpsConfig.cjs");
const perpsErrorCodes_1 = require("../perpsErrorCodes.cjs");
/**
 * Validation utilities for HyperLiquid operations
 */
/**
 * Create standardized error response.
 *
 * @param error - The error that occurred
 * @param defaultResponse - The default response object to use as template
 * @returns The error response with success=false and error message
 */
function createErrorResult(error, defaultResponse) {
    return {
        ...defaultResponse,
        success: false,
        error: error instanceof Error ? error.message : perpsErrorCodes_1.PERPS_ERROR_CODES.UNKNOWN_ERROR,
    };
}
exports.createErrorResult = createErrorResult;
/**
 * Validate withdrawal parameters.
 *
 * @param params - Withdrawal parameters to validate
 * @param params.assetId - The CAIP asset ID to withdraw
 * @param params.amount - Amount to withdraw as string
 * @param params.destination - Optional destination hex address
 * @param debugLogger - Optional debug logger for detailed logging
 * @returns Validation result with isValid flag and optional error message
 */
function validateWithdrawalParams(params, debugLogger) {
    debugLogger?.log('validateWithdrawalParams: Starting validation', {
        params,
        hasAssetId: Boolean(params.assetId),
        hasAmount: Boolean(params.amount),
        hasDestination: Boolean(params.destination),
    });
    // Validate required parameters
    if (!params.assetId) {
        debugLogger?.log('validateWithdrawalParams: Missing assetId', {
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.WITHDRAW_ASSET_ID_REQUIRED,
            params,
        });
        return {
            isValid: false,
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.WITHDRAW_ASSET_ID_REQUIRED,
        };
    }
    // Validate amount
    if (!params.amount) {
        debugLogger?.log('validateWithdrawalParams: Missing amount', {
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.WITHDRAW_AMOUNT_REQUIRED,
            params,
        });
        return {
            isValid: false,
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.WITHDRAW_AMOUNT_REQUIRED,
        };
    }
    const amount = parseFloat(params.amount);
    if (isNaN(amount) || amount <= 0) {
        debugLogger?.log('validateWithdrawalParams: Invalid amount', {
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.WITHDRAW_AMOUNT_POSITIVE,
            amount: params.amount,
            parsedAmount: amount,
            isNaN: isNaN(amount),
        });
        return {
            isValid: false,
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.WITHDRAW_AMOUNT_POSITIVE,
        };
    }
    // Validate destination address if provided
    if (params.destination && !(0, utils_1.isValidHexAddress)(params.destination)) {
        debugLogger?.log('validateWithdrawalParams: Invalid destination address', {
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.WITHDRAW_INVALID_DESTINATION,
            destination: params.destination,
            isValidHex: (0, utils_1.isValidHexAddress)(params.destination),
        });
        return {
            isValid: false,
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.WITHDRAW_INVALID_DESTINATION,
        };
    }
    debugLogger?.log('validateWithdrawalParams: All validations passed', {
        assetId: params.assetId,
        amount: params.amount,
        destination: params.destination ?? 'will use user wallet',
    });
    return { isValid: true };
}
exports.validateWithdrawalParams = validateWithdrawalParams;
/**
 * Validate deposit parameters.
 *
 * @param params - Deposit parameters to validate
 * @param params.assetId - The CAIP asset ID to deposit
 * @param params.amount - Amount to deposit as string
 * @param params.isTestnet - Whether this is a testnet deposit
 * @param debugLogger - Optional debug logger for detailed logging
 * @returns Validation result with isValid flag and optional error message
 */
function validateDepositParams(params, debugLogger) {
    debugLogger?.log('validateDepositParams: Starting validation', {
        params,
        hasAssetId: Boolean(params.assetId),
        hasAmount: Boolean(params.amount),
        isTestnet: params.isTestnet,
    });
    // Validate required parameters
    if (!params.assetId) {
        debugLogger?.log('validateDepositParams: Missing assetId', {
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.DEPOSIT_ASSET_ID_REQUIRED,
            params,
        });
        return {
            isValid: false,
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.DEPOSIT_ASSET_ID_REQUIRED,
        };
    }
    // Validate amount
    if (!params.amount) {
        debugLogger?.log('validateDepositParams: Missing amount', {
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.DEPOSIT_AMOUNT_REQUIRED,
            params,
        });
        return {
            isValid: false,
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.DEPOSIT_AMOUNT_REQUIRED,
        };
    }
    const amount = parseFloat(params.amount);
    if (isNaN(amount) || amount <= 0) {
        debugLogger?.log('validateDepositParams: Invalid amount', {
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.DEPOSIT_AMOUNT_POSITIVE,
            amount: params.amount,
            parsedAmount: amount,
            isNaN: isNaN(amount),
        });
        return {
            isValid: false,
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.DEPOSIT_AMOUNT_POSITIVE,
        };
    }
    // Check minimum deposit amount
    const minimumAmount = params.isTestnet
        ? hyperLiquidConfig_1.TRADING_DEFAULTS.amount.testnet
        : hyperLiquidConfig_1.TRADING_DEFAULTS.amount.mainnet;
    debugLogger?.log('validateDepositParams: Checking minimum amount', {
        amount,
        minimumAmount,
        isTestnet: params.isTestnet,
        network: params.isTestnet ? 'testnet' : 'mainnet',
    });
    if (amount < minimumAmount) {
        debugLogger?.log('validateDepositParams: Below minimum deposit', {
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.DEPOSIT_MINIMUM_AMOUNT,
            amount,
            minimumAmount,
            difference: minimumAmount - amount,
        });
        return {
            isValid: false,
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.DEPOSIT_MINIMUM_AMOUNT,
        };
    }
    debugLogger?.log('validateDepositParams: All validations passed', {
        assetId: params.assetId,
        amount: params.amount,
        parsedAmount: amount,
        minimumAmount,
        isTestnet: params.isTestnet,
    });
    return { isValid: true };
}
exports.validateDepositParams = validateDepositParams;
/**
 * Validate asset support for withdrawals using AssetRoute arrays.
 *
 * @param assetId - The CAIP asset ID to validate
 * @param supportedRoutes - Array of supported asset routes
 * @param debugLogger - Optional debug logger for detailed logging
 * @returns Validation result with isValid flag and optional error message
 */
function validateAssetSupport(assetId, supportedRoutes, debugLogger) {
    debugLogger?.log('validateAssetSupport: Checking asset support', {
        assetId,
        supportedRoutesCount: supportedRoutes.length,
    });
    const supportedAssetIds = supportedRoutes.map((route) => route.assetId);
    // Check if asset is supported
    const isSupported = supportedAssetIds.includes(assetId);
    if (!isSupported) {
        // Also check case-insensitive match for contract addresses
        const isSupportedCaseInsensitive = supportedAssetIds.some((supportedId) => supportedId.toLowerCase() === assetId.toLowerCase());
        if (!isSupportedCaseInsensitive) {
            debugLogger?.log('validateAssetSupport: Asset not supported', {
                error: perpsErrorCodes_1.PERPS_ERROR_CODES.WITHDRAW_ASSET_NOT_SUPPORTED,
                assetId,
                supportedAssetIds,
                checkedCaseInsensitive: true,
            });
            return {
                isValid: false,
                error: perpsErrorCodes_1.PERPS_ERROR_CODES.WITHDRAW_ASSET_NOT_SUPPORTED,
            };
        }
        debugLogger?.log('⚠️ validateAssetSupport: Asset supported with case mismatch', {
            providedAssetId: assetId,
            matchedAssetId: supportedAssetIds.find((id) => id.toLowerCase() === assetId.toLowerCase()),
        });
    }
    debugLogger?.log('validateAssetSupport: Asset is supported', {
        assetId,
    });
    return { isValid: true };
}
exports.validateAssetSupport = validateAssetSupport;
/**
 * Validate balance against withdrawal amount.
 *
 * @param withdrawAmount - The amount to withdraw
 * @param withdrawableBalance - Max USD that can leave the venue right now
 * @param debugLogger - Optional debug logger for detailed logging
 * @returns Validation result with isValid flag and optional error message
 */
function validateBalance(withdrawAmount, withdrawableBalance, debugLogger) {
    debugLogger?.log('validateBalance: Checking balance sufficiency', {
        withdrawAmount,
        withdrawableBalance,
        difference: withdrawableBalance - withdrawAmount,
    });
    if (withdrawAmount > withdrawableBalance) {
        const shortfall = withdrawAmount - withdrawableBalance;
        debugLogger?.log('validateBalance: Insufficient balance', {
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.WITHDRAW_INSUFFICIENT_BALANCE,
            withdrawAmount,
            withdrawableBalance,
            shortfall,
            percentageOfAvailable: `${((withdrawAmount / withdrawableBalance) * 100).toFixed(2)}%`,
        });
        return {
            isValid: false,
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.WITHDRAW_INSUFFICIENT_BALANCE,
        };
    }
    const remainingBalance = withdrawableBalance - withdrawAmount;
    debugLogger?.log('validateBalance: Balance is sufficient', {
        withdrawAmount,
        withdrawableBalance,
        remainingBalance,
        percentageUsed: `${((withdrawAmount / withdrawableBalance) * 100).toFixed(2)}%`,
    });
    return { isValid: true };
}
exports.validateBalance = validateBalance;
/**
 * Apply filters to asset paths with comprehensive logging.
 *
 * @param assets - Array of CAIP asset IDs to filter
 * @param params - Filter parameters including chainId, symbol, and assetId
 * @param debugLogger - Optional debug logger for detailed logging
 * @returns Filtered array of CAIP asset IDs
 */
function applyPathFilters(assets, params, debugLogger) {
    if (!params) {
        debugLogger?.log('HyperLiquid: applyPathFilters - no params, returning all assets', { assets });
        return assets;
    }
    let filtered = assets;
    debugLogger?.log('HyperLiquid: applyPathFilters - starting filter', {
        initialAssets: assets,
        filterParams: params,
    });
    if (params.chainId) {
        const before = filtered;
        filtered = filtered.filter((asset) => asset.startsWith(params.chainId));
        debugLogger?.log('HyperLiquid: applyPathFilters - chainId filter', {
            chainId: params.chainId,
            before,
            after: filtered,
        });
    }
    // Note: `in` is the idiomatic TypeScript way to narrow a string to
    // `keyof typeof` for indexed access; `hasProperty` types the indexed
    // result as `unknown` and loses the `{ testnet, mainnet }` shape.
    /* eslint-disable-next-line no-restricted-syntax */
    if (params.symbol && params.symbol in hyperLiquidConfig_1.HYPERLIQUID_ASSET_CONFIGS) {
        const config = hyperLiquidConfig_1.HYPERLIQUID_ASSET_CONFIGS[params.symbol];
        const isTestnet = params.isTestnet ?? false;
        const selectedAsset = isTestnet ? config.testnet : config.mainnet;
        const before = filtered;
        filtered = [selectedAsset];
        debugLogger?.log('HyperLiquid: applyPathFilters - symbol filter', {
            symbol: params.symbol,
            isTestnet,
            config,
            selectedAsset,
            before,
            after: filtered,
        });
    }
    if (params.assetId) {
        const before = filtered;
        // Use case-insensitive comparison for asset ID matching to handle address case differences
        filtered = filtered.filter((asset) => asset.toLowerCase() === params.assetId?.toLowerCase());
        debugLogger?.log('HyperLiquid: applyPathFilters - assetId filter', {
            assetId: params.assetId,
            before,
            after: filtered,
            exactMatch: before.includes(params.assetId),
            caseInsensitiveMatch: before.some((asset) => asset.toLowerCase() === params.assetId?.toLowerCase()),
        });
    }
    debugLogger?.log('HyperLiquid: applyPathFilters - final result', {
        initialAssets: assets,
        finalFiltered: filtered,
        filterParams: params,
    });
    return filtered;
}
exports.applyPathFilters = applyPathFilters;
/**
 * Get supported deposit/withdrawal paths with filtering.
 *
 * @param params - Filter parameters including isTestnet, chainId, symbol
 * @param debugLogger - Optional debug logger for detailed logging
 * @returns Array of supported CAIP asset IDs
 */
function getSupportedPaths(params, debugLogger) {
    const isTestnet = params?.isTestnet ?? false;
    const assets = (0, hyperLiquidConfig_1.getSupportedAssets)(isTestnet);
    const filteredAssets = applyPathFilters(assets, params, debugLogger);
    debugLogger?.log('HyperLiquid: getSupportedPaths', {
        isTestnet,
        requestedParams: params,
        allAssets: assets,
        filteredAssets,
        returnType: 'CaipAssetId[]',
        example: filteredAssets[0],
    });
    return filteredAssets;
}
exports.getSupportedPaths = getSupportedPaths;
/**
 * Get maximum order value based on leverage and order type.
 * Based on HyperLiquid contract specifications.
 *
 * @param maxLeverage - The maximum leverage for the market
 * @param orderType - The order type (market or limit)
 * @returns Maximum order value in USD
 */
function getMaxOrderValue(maxLeverage, orderType) {
    let marketLimit;
    if (maxLeverage >= 25) {
        marketLimit = perpsConfig_1.HYPERLIQUID_ORDER_LIMITS.MarketOrderLimits.HighLeverage;
    }
    else if (maxLeverage >= 20) {
        marketLimit = perpsConfig_1.HYPERLIQUID_ORDER_LIMITS.MarketOrderLimits.MediumHighLeverage;
    }
    else if (maxLeverage >= 10) {
        marketLimit = perpsConfig_1.HYPERLIQUID_ORDER_LIMITS.MarketOrderLimits.MediumLeverage;
    }
    else {
        marketLimit = perpsConfig_1.HYPERLIQUID_ORDER_LIMITS.MarketOrderLimits.LowLeverage;
    }
    return orderType === 'limit'
        ? marketLimit * perpsConfig_1.HYPERLIQUID_ORDER_LIMITS.LimitOrderMultiplier
        : marketLimit;
}
exports.getMaxOrderValue = getMaxOrderValue;
/**
 * Validate order parameters.
 * Basic validation - checks required fields are present.
 * Amount validation (size/USD) is handled by validateOrder.
 *
 * @param params - Order parameters to validate
 * @param params.coin - The trading pair coin symbol
 * @param params.size - The order size as string
 * @param params.price - The order price as string
 * @param params.orderType - The order type (market or limit)
 * @returns Validation result with isValid flag and optional error message
 */
function validateOrderParams(params) {
    if (!params.coin) {
        return {
            isValid: false,
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.ORDER_COIN_REQUIRED,
        };
    }
    // Note: Size validation removed - validateOrder handles amount validation using USD as source of truth
    // Require price for limit orders
    if (params.orderType === 'limit' && !params.price) {
        return {
            isValid: false,
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.ORDER_LIMIT_PRICE_REQUIRED,
        };
    }
    if (params.price && parseFloat(params.price) <= 0) {
        return {
            isValid: false,
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.ORDER_PRICE_POSITIVE,
        };
    }
    return { isValid: true };
}
exports.validateOrderParams = validateOrderParams;
/**
 * Validate coin exists in asset mapping.
 *
 * @param coin - The coin symbol to validate
 * @param coinToAssetId - Map of coin symbols to asset IDs
 * @returns Validation result with isValid flag and optional error message
 */
function validateCoinExists(coin, coinToAssetId) {
    if (!coinToAssetId.has(coin)) {
        return {
            isValid: false,
            error: perpsErrorCodes_1.PERPS_ERROR_CODES.ORDER_UNKNOWN_COIN,
        };
    }
    return { isValid: true };
}
exports.validateCoinExists = validateCoinExists;
//# sourceMappingURL=hyperLiquidValidation.cjs.map