"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.testGetDefaultArbitrageStrategy = exports.getArbitrageStrategies = exports.validateAndParseArbitrageStrategy = exports.upTo10TokenUnitsReasonableSettings = exports.defaultSettings = void 0;
const tslib_1 = require("tslib");
const ethers_1 = require("ethers");
const zod_1 = require("zod");
const lodash_merge_1 = tslib_1.__importDefault(require("lodash.merge"));
const logger_1 = require("../utils/logger");
const enums_1 = require("../pricer/enums");
const types_1 = require("../pricer/types");
const error_1 = require("../utils/error");
const config_1 = tslib_1.__importDefault(require("./config"));
const bigNumberSchema = zod_1.z.string().refine((data) => !Number.isNaN(Number.parseFloat(data)), {
    message: 'Invalid BigNumber format',
});
const orderArbitrageStrategySchema = zod_1.z.object({
    minProfitPerOrder: zod_1.z.number(),
    minProfitRate: zod_1.z.number(),
    maxAmountPerOrder: bigNumberSchema,
    minAmountPerOrder: bigNumberSchema,
    maxShareOfMyBalancePerOrder: zod_1.z.number(),
});
exports.defaultSettings = {
    minProfitPerOrder: 0.0001, // 0.0001 USD
    minProfitRate: 0.001, // 0.001%
    maxAmountPerOrder: ethers_1.ethers.utils.parseEther('50000'),
    minAmountPerOrder: ethers_1.ethers.utils.parseEther('0'),
    maxShareOfMyBalancePerOrder: 40,
};
const ONE_ON_18_DECIMALS = 10 ** 18;
// min profit per order: represents a specific amount
// min amount to pick up: 0.00004 UNIT of target asset
// max amount to pick up: 10 UNIT of target asset
exports.upTo10TokenUnitsReasonableSettings = {
    minProfitPerOrder: 0.0001,
    minProfitRate: 0,
    maxAmountPerOrder: ethers_1.BigNumber.from((10 * ONE_ON_18_DECIMALS).toString()),
    minAmountPerOrder: ethers_1.BigNumber.from((0.00004 * ONE_ON_18_DECIMALS).toString()),
    maxShareOfMyBalancePerOrder: 40,
};
const enabledAssets = config_1.default.executor.enabledAssets
    .filter((asset) => typeof asset === 'string' && asset.trim().length > 0)
    .map((asset) => asset.toLowerCase());
const defaultStrategy = Object.fromEntries(enabledAssets.map((asset) => [asset, { ...exports.defaultSettings }]));
const DEFAULT_ARBITRAGE_STRATEGY = {
    /*
     * Mainnets
     */
    arbm: defaultStrategy,
    basm: defaultStrategy,
    bscm: defaultStrategy,
    blsm: defaultStrategy,
    ethm: defaultStrategy,
    optm: defaultStrategy,
    scrm: defaultStrategy,
    l3rn: defaultStrategy,
    t3rn: defaultStrategy,
    linm: defaultStrategy,
    /*
     * Testnets
     */
    arbt: defaultStrategy,
    bast: defaultStrategy,
    bsct: defaultStrategy,
    blst: defaultStrategy,
    lint: defaultStrategy,
    opst: defaultStrategy,
    scrt: defaultStrategy,
    l0rn: defaultStrategy,
    l1rn: defaultStrategy,
    l2rn: defaultStrategy,
    t1rn: defaultStrategy,
    t2rn: defaultStrategy,
    /*
     * Local dev
     */
    lol3: defaultStrategy,
    lols: defaultStrategy,
    lold: defaultStrategy,
    /*
     * Testnets season 2
     */
    bert: defaultStrategy,
    berm: defaultStrategy,
    abst: defaultStrategy,
    absm: defaultStrategy,
    lskt: defaultStrategy,
    lskm: defaultStrategy,
    unit: defaultStrategy,
    unim: defaultStrategy,
    seit: defaultStrategy,
    mont: defaultStrategy,
};
/**
 * Validates and parses the provided strategy object.
 *
 * @param {ArbitrageStrategiesInput} strategy
 * @returns {OrderArbitrageStrategies}
 */
const validateAndParseArbitrageStrategy = (strategy) => {
    if (Object.keys(strategy ?? {}).length === 0) {
        throw new Error('No arbitrage strategy provided');
    }
    const arbitrageStrategies = {};
    const supportedAssets = Object.values(enums_1.AssetName);
    for (const [networkId, arbitrageConfigForNetwork] of Object.entries(strategy)) {
        if (!(0, types_1.isSupportedNetworkT3rn)(networkId)) {
            throw new Error(`Unsupported arbitrage strategy network: ${networkId}`);
        }
        arbitrageStrategies[networkId] = {};
        for (const [assetName, arbitrageConfigForAsset] of Object.entries(arbitrageConfigForNetwork)) {
            if (!supportedAssets.includes(assetName)) {
                throw new Error(`Unsupported arbitrage strategy asset: ${assetName} Network: ${networkId}`);
            }
            try {
                orderArbitrageStrategySchema.parse(arbitrageConfigForAsset);
            }
            catch (error) {
                const err = (0, error_1.shallowExtractErrorDetails)(error);
                throw new Error(`Invalid arbitrage strategy. Asset: ${assetName} Network: ${networkId} Error: ${err.message}`);
            }
            arbitrageStrategies[networkId][assetName] = {
                minProfitPerOrder: arbitrageConfigForAsset.minProfitPerOrder,
                minProfitRate: arbitrageConfigForAsset.minProfitRate,
                maxAmountPerOrder: ethers_1.ethers.utils.parseEther(arbitrageConfigForAsset.maxAmountPerOrder),
                minAmountPerOrder: ethers_1.ethers.utils.parseEther(arbitrageConfigForAsset.minAmountPerOrder),
                maxShareOfMyBalancePerOrder: arbitrageConfigForAsset.maxShareOfMyBalancePerOrder,
            };
        }
    }
    return arbitrageStrategies;
};
exports.validateAndParseArbitrageStrategy = validateAndParseArbitrageStrategy;
/**
 * Sets or gets a valid arbitrage strategy for the executor.
 * Returns valid arbitrage strategy for the executor.
 *
 * If no custom strategy object provided, returns the default strategy.
 * If the custom one provided is invalid, returns the default strategy.
 *
 * Merges the provided one with the default one, replacing properties (networks or assets) from the
 * default one with the provided ones.
 *
 * @param {object=}  strategy The strategy should already be a valid JSON object
 * @returns {OrderArbitrageStrategies}
 */
const getArbitrageStrategies = (strategy) => {
    if (!strategy) {
        logger_1.logger.info('🪆 No custom arbitrage strategy provided. Using default.');
        // TODO: This log breaks tests
        // logger.debug('Custom arbitrage strategy not provided. Using default strategy.')
        return DEFAULT_ARBITRAGE_STRATEGY;
    }
    logger_1.logger.info({ strategy: JSON.stringify(strategy) }, '🪆 Provided custom arbitrage strategy');
    let arbitrageStrategies;
    try {
        arbitrageStrategies = (0, exports.validateAndParseArbitrageStrategy)(strategy);
    }
    catch (error) {
        logger_1.logger.error({ error: error.message }, `Provided arbitrage strategy has invalid JSON format. Fallback to using default strategy.`);
        return DEFAULT_ARBITRAGE_STRATEGY;
    }
    return (0, lodash_merge_1.default)({}, DEFAULT_ARBITRAGE_STRATEGY, arbitrageStrategies);
};
exports.getArbitrageStrategies = getArbitrageStrategies;
/*
 * ====== functions used only in testing ======
 */
const testGetDefaultArbitrageStrategy = () => {
    return DEFAULT_ARBITRAGE_STRATEGY;
};
exports.testGetDefaultArbitrageStrategy = testGetDefaultArbitrageStrategy;
//# sourceMappingURL=executor-arbitrage-strategies.js.map