"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());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAllIsolationModeTokensFromContractPositions = exports.getVaultAddresses = exports.getTokenBalancesPerAccountStructLib = exports.mapTokensToDolomiteDataProps = exports.getTokenDefinitionsLib = exports.chunkArrayForMultiCall = exports.DOLOMITE_GRAPH_ENDPOINT = exports.DOLOMITE_AMM_FACTORY_ADDRESSES = exports.DOLOMITE_MARGIN_ADDRESSES = exports.SPECIAL_TOKEN_NAME_MATCHERS = exports.SILO_MODE_MATCHERS = exports.ISOLATION_MODE_MATCHERS = exports.CHUNK_SIZE = exports.TokenMode = void 0;
const ethers_1 = require("ethers");
const ethers_2 = require("../../../apps/dolomite/contracts/ethers");
const position_interface_1 = require("../../../position/position.interface");
const _types_1 = require("../../../types");
var TokenMode;
(function (TokenMode) {
    TokenMode["NORMAL"] = "NORMAL";
    TokenMode["ISOLATION"] = "ISOLATION";
    TokenMode["SILO"] = "SILO";
})(TokenMode = exports.TokenMode || (exports.TokenMode = {}));
exports.CHUNK_SIZE = 32;
exports.ISOLATION_MODE_MATCHERS = ['Dolomite Isolation:', 'Dolomite: Fee + Staked GLP'];
exports.SILO_MODE_MATCHERS = ['Dolomite Silo:'];
exports.SPECIAL_TOKEN_NAME_MATCHERS = [...exports.ISOLATION_MODE_MATCHERS, ...exports.SILO_MODE_MATCHERS];
exports.DOLOMITE_MARGIN_ADDRESSES = {
    [_types_1.Network.ARBITRUM_MAINNET]: '0x6bd780e7fdf01d77e4d475c821f1e7ae05409072',
};
exports.DOLOMITE_AMM_FACTORY_ADDRESSES = {
    [_types_1.Network.ARBITRUM_MAINNET]: '0xd99c21c96103f36bc1fa26dd6448af4da030c1ef',
};
exports.DOLOMITE_GRAPH_ENDPOINT = 'https://api.thegraph.com/subgraphs/name/dolomite-exchange/dolomite-v2-arbitrum';
const ONE_DOLLAR = ethers_1.BigNumber.from('1000000000000000000000000000000000000');
const ONE_INDEX = ethers_1.BigNumber.from('1000000000000000000');
function chunkArrayForMultiCall(values, getCallData) {
    const callChunks = [];
    let index = 0;
    for (let i = 0; i < values.length; i += exports.CHUNK_SIZE) {
        callChunks[i] = [];
        for (let j = 0; j < exports.CHUNK_SIZE && index < values.length; j++) {
            callChunks[i / exports.CHUNK_SIZE].push(getCallData(values[i + j], i + j));
            index += 1;
        }
    }
    return callChunks;
}
exports.chunkArrayForMultiCall = chunkArrayForMultiCall;
function getTokenDefinitionsLib(params, network) {
    return __awaiter(this, void 0, void 0, function* () {
        const tokens = [];
        for (let i = 0; i < params.definition.marketsCount; i++) {
            tokens.push({
                address: params.definition.marketIdToMarketMap[i].underlyingTokenAddress,
                network: network,
                metaType: position_interface_1.MetaType.SUPPLIED,
            });
        }
        return tokens;
    });
}
exports.getTokenDefinitionsLib = getTokenDefinitionsLib;
function mapTokensToDolomiteDataProps(params, isFetchingDolomiteBalances, multicall) {
    return __awaiter(this, void 0, void 0, function* () {
        let liquidity = undefined;
        if (isFetchingDolomiteBalances) {
            liquidity = 0;
            for (let i = 0; i < params.definition.marketsCount; i++) {
                const contract = multicall.wrap(params.contract);
                const totalPar = yield contract.getMarketTotalPar(i);
                const index = yield contract.getMarketCurrentIndex(i);
                const totalSupply = totalPar.supply.mul(index.supply).div(ONE_INDEX);
                const totalBorrow = totalPar.borrow.mul(index.borrow).div(ONE_INDEX);
                const price = (yield contract.getMarketPrice(i)).value;
                liquidity += totalSupply.sub(totalBorrow).mul(price).div(ONE_DOLLAR.div(100000)).toNumber() / 100000.0;
            }
        }
        return {
            liquidity,
            marketsCount: params.definition.marketsCount,
            marketIdToMarketMap: params.definition.marketIdToMarketMap,
        };
    });
}
exports.mapTokensToDolomiteDataProps = mapTokensToDolomiteDataProps;
function getTokenBalancesPerAccountStructLib(params, accountStruct) {
    return __awaiter(this, void 0, void 0, function* () {
        const tokenAddressToAmount = new Map();
        const [marketIds, tokenAddresses, , weiAmounts] = yield params.contract.getAccountBalances({
            owner: accountStruct.accountOwner,
            number: accountStruct.accountNumber,
        });
        tokenAddresses.forEach((tokenAddress, i) => {
            let amount = ethers_1.BigNumber.from(weiAmounts[i].value);
            if (!weiAmounts[i].sign) {
                amount = amount.mul(-1);
            }
            const marketId = marketIds[i].toNumber();
            tokenAddress = params.contractPosition.dataProps.marketIdToMarketMap[marketId].underlyingTokenAddress;
            tokenAddressToAmount.set(tokenAddress, amount);
        });
        return tokenAddressToAmount;
    });
}
exports.getTokenBalancesPerAccountStructLib = getTokenBalancesPerAccountStructLib;
function getVaultAddresses(account, isolationModeTokenAddresses, multicall) {
    return __awaiter(this, void 0, void 0, function* () {
        const calls = isolationModeTokenAddresses.map(tokenAddress => {
            return {
                target: tokenAddress,
                callData: ethers_2.IsolationModeToken__factory.createInterface().encodeFunctionData('getVaultByAccount', [account]),
            };
        });
        const results = yield multicall.callStatic.aggregate(calls, true);
        return results.returnData.map(({ data }) => {
            return ethers_1.ethers.utils.defaultAbiCoder.decode(['address'], data)[0].toLowerCase();
        });
    });
}
exports.getVaultAddresses = getVaultAddresses;
function getAllIsolationModeTokensFromContractPositions(account, contractPositions, multicall) {
    return __awaiter(this, void 0, void 0, function* () {
        const isolationModeTokensMap = contractPositions.reduce((memo, position) => {
            position.tokens.forEach((token, i) => {
                const extraData = position.dataProps.marketIdToMarketMap[i];
                if (!memo[token.address] && extraData.mode === TokenMode.ISOLATION) {
                    memo[token.address] = extraData.wrappedTokenAddress;
                }
            });
            return memo;
        }, {});
        const isolationModeTokens = Object.values(isolationModeTokensMap);
        return getVaultAddresses(account, isolationModeTokens, multicall.contract);
    });
}
exports.getAllIsolationModeTokensFromContractPositions = getAllIsolationModeTokensFromContractPositions;
//# sourceMappingURL=utils.js.map