"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.encodeSubAccountId = exports.computePositionPnlUsd = exports.getCollateralTokensByNetwork = exports.getMarketTokensByNetwork = exports.fromWei = exports.formatMetaBaseData = exports.READER_ADDRESS = exports.ASSET_IS_STRICT_STABLE = exports.ASSET_IS_ENABLED = exports.ASSET_USE_STABLE_TOKEN_FOR_PROFIT = exports.ASSET_IS_SHORTABLE = exports.ASSET_IS_OPENABLE = exports.ASSET_IS_TRADABLE = exports.ASSET_CAN_ADD_REMOVE_LIQUIDITY = exports.ASSET_IS_STABLE = exports.RATIO_DECIMALS = exports.DECIMALS = exports._0 = void 0;
const bignumber_js_1 = require("bignumber.js");
const ethers_1 = require("ethers");
const lodash_1 = __importDefault(require("lodash"));
const address_1 = require("../../../app-toolkit/constants/address");
const network_interface_1 = require("../../../types/network.interface");
const contracts_1 = require("../contracts");
exports._0 = new bignumber_js_1.BigNumber('0');
exports.DECIMALS = 18;
exports.RATIO_DECIMALS = 5;
exports.ASSET_IS_STABLE = 0x00000000000001;
exports.ASSET_CAN_ADD_REMOVE_LIQUIDITY = 0x00000000000002;
exports.ASSET_IS_TRADABLE = 0x00000000000100;
exports.ASSET_IS_OPENABLE = 0x00000000010000;
exports.ASSET_IS_SHORTABLE = 0x00000001000000;
exports.ASSET_USE_STABLE_TOKEN_FOR_PROFIT = 0x00000100000000;
exports.ASSET_IS_ENABLED = 0x00010000000000;
exports.ASSET_IS_STRICT_STABLE = 0x01000000000000;
exports.READER_ADDRESS = {
    [network_interface_1.Network.ARBITRUM_MAINNET]: '0x6e29c4e8095b2885b8d30b17790924f33ecd7b33',
    [network_interface_1.Network.BINANCE_SMART_CHAIN_MAINNET]: '0xeab5b06a1ea173674601dd54c612542b563beca1',
    [network_interface_1.Network.AVALANCHE_MAINNET]: '0x5996d4545ee59d96cb1fe8661a028bef0f4744b0',
    [network_interface_1.Network.FANTOM_OPERA_MAINNET]: '0x29f4dc996a0219838afecf868362e4df28a70a7b',
};
function formatMetaBaseData(cols, rows) {
    const keys = cols.map(col => {
        return col.display_name;
    });
    return rows.map(row => {
        const obj = {};
        row.map((item, index) => {
            obj[keys[index]] = item;
        });
        return obj;
    });
}
exports.formatMetaBaseData = formatMetaBaseData;
function and64(v1, v2) {
    const hi = 0x80000000;
    const low = 0x7fffffff;
    const hi1 = ~~(v1 / hi);
    const hi2 = ~~(v2 / hi);
    const low1 = v1 & low;
    const low2 = v2 & low;
    const h = hi1 & hi2;
    const l = low1 & low2;
    return h * hi + l;
}
function test64(v1, mask) {
    return and64(v1, mask) !== 0;
}
function fromRate(n) {
    return new bignumber_js_1.BigNumber(n.toString()).shiftedBy(-exports.RATIO_DECIMALS);
}
function fromWei(n) {
    return new bignumber_js_1.BigNumber(n.toString()).shiftedBy(-exports.DECIMALS);
}
exports.fromWei = fromWei;
function getReaderAssets(network, appToolkit) {
    return __awaiter(this, void 0, void 0, function* () {
        const multicall = appToolkit.getMulticall(network);
        const readerContract = new contracts_1.MuxContractFactory(appToolkit).muxReader({ address: exports.READER_ADDRESS[network], network });
        const storage = yield multicall.wrap(readerContract).callStatic.getChainStorage();
        return storage[1]
            .filter(item => item.tokenAddress !== address_1.ZERO_ADDRESS)
            .map(a => {
            return {
                symbol: ethers_1.ethers.utils.parseBytes32String(a.symbol),
                id: a.id,
                tokenAddress: a.tokenAddress,
                decimals: a.decimals,
                isStable: test64(a.flags.toNumber(), exports.ASSET_IS_STABLE),
                isTradable: test64(a.flags.toNumber(), exports.ASSET_IS_TRADABLE),
                isOpenable: test64(a.flags.toNumber(), exports.ASSET_IS_OPENABLE),
                useStableTokenForProfit: test64(a.flags.toNumber(), exports.ASSET_USE_STABLE_TOKEN_FOR_PROFIT),
                isEnabled: test64(a.flags.toNumber(), exports.ASSET_IS_ENABLED),
                minProfitTime: a.minProfitTime,
                minProfitRate: fromRate(a.minProfitRate),
            };
        });
    });
}
function getMarketTokensByNetwork(network, appToolkit) {
    return __awaiter(this, void 0, void 0, function* () {
        const baseTokens = yield appToolkit.getBaseTokenPrices(network);
        const assets = yield getReaderAssets(network, appToolkit);
        return lodash_1.default.compact(assets
            .filter(item => !item.isStable && item.isTradable && item.isOpenable && item.isEnabled)
            .map(token => {
            const marketToken = baseTokens.find(x => x.address === token.tokenAddress.toLowerCase());
            if (!marketToken) {
                return;
            }
            return Object.assign(Object.assign({}, marketToken), { muxTokenId: token.id, minProfitTime: token.minProfitTime, minProfitRate: token.minProfitRate });
        }));
    });
}
exports.getMarketTokensByNetwork = getMarketTokensByNetwork;
function getCollateralTokensByNetwork(network, appToolkit) {
    return __awaiter(this, void 0, void 0, function* () {
        const baseTokens = yield appToolkit.getBaseTokenPrices(network);
        const assets = yield getReaderAssets(network, appToolkit);
        return lodash_1.default.compact(assets
            .filter(item => !item.useStableTokenForProfit && item.isEnabled)
            .map(token => {
            const collateralToken = baseTokens.find(x => x.address === token.tokenAddress.toLowerCase());
            if (!collateralToken) {
                return;
            }
            return Object.assign(Object.assign({}, collateralToken), { muxTokenId: token.id, minProfitTime: token.minProfitTime, minProfitRate: token.minProfitRate });
        }));
    });
}
exports.getCollateralTokensByNetwork = getCollateralTokensByNetwork;
function computePositionPnlUsd(assetPrice, assetMinProfitTime, assetMinProfitRate, amount, entryPrice, lastIncreasedTime, isLong) {
    if (new bignumber_js_1.BigNumber(amount).eq(exports._0))
        return { pendingPnlUsd: exports._0, pnlUsd: exports._0 };
    const priceDelta = isLong ? new bignumber_js_1.BigNumber(assetPrice).minus(entryPrice) : new bignumber_js_1.BigNumber(entryPrice).minus(assetPrice);
    const pendingPnlUsd = priceDelta.times(amount);
    const isPendingMinTime = Math.ceil(Date.now() / 1000) < lastIncreasedTime + assetMinProfitTime;
    const isPendingMinProfitRate = priceDelta.abs().lt(new bignumber_js_1.BigNumber(assetMinProfitRate).times(entryPrice));
    if (priceDelta.gt(exports._0) && isPendingMinTime && isPendingMinProfitRate)
        return { pendingPnlUsd, pnlUsd: exports._0 };
    return { pendingPnlUsd, pnlUsd: pendingPnlUsd };
}
exports.computePositionPnlUsd = computePositionPnlUsd;
function encodeSubAccountId(account, collateralId, assetId, isLong) {
    if (ethers_1.ethers.utils.arrayify(account).length !== 20)
        return null;
    const params = [account, collateralId, assetId, isLong];
    const packed = ethers_1.ethers.utils.solidityPack(['address', 'uint8', 'uint8', 'bool'], params);
    const padded = packed + '000000000000000000';
    return padded;
}
exports.encodeSubAccountId = encodeSubAccountId;
//# sourceMappingURL=utils.js.map