"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getUserWalletData = exports.getUserTrancheData = exports.getUserSummaryData = exports.getTrancheAssetData = exports.getTrancheData = exports.getAllTrancheData = exports.getTrancheMarketsData = exports.getTopAssets = exports.getProtocolData = exports.getAllMarketsData = exports.getTotalMarkets = exports.getTotalTranches = void 0;
const constants_1 = require("./constants");
const ethers_1 = require("ethers");
const contract_getters_1 = require("./contract-getters");
const decode_bytecode_1 = require("./decode-bytecode");
const utils_1 = require("./utils");
/**
 * PROTOCOL LEVEL ANALYTICS
 */
async function getTotalTranches(params, callback) {
    let configurator = await contract_getters_1.getLendingPoolConfiguratorProxy(params);
    const totalTranches = (await configurator.totalTranches()).toNumber();
    return totalTranches;
}
exports.getTotalTranches = getTotalTranches;
async function getTotalMarkets(params, callback) {
    const cacheKey = "total-markets";
    const cachedTotalMarkets = await utils_1.cache.getItem(cacheKey);
    if (cachedTotalMarkets) {
        return cachedTotalMarkets;
    }
    await getAllMarketsData(params);
    return await utils_1.cache.getItem(cacheKey);
}
exports.getTotalMarkets = getTotalMarkets;
async function getAllMarketsData(params, callback) {
    const numTranches = await getTotalTranches(params);
    const allMarketsData = [];
    for (let i = 0; i < numTranches; i++) {
        allMarketsData.push(...(await getTrancheMarketsData({
            tranche: i,
            network: params.network,
            test: params.test,
        })));
    }
    // await cache.setItem("total-markets", allMarketsData.length, { ttl: 60 });
    return allMarketsData;
}
exports.getAllMarketsData = getAllMarketsData;
async function getProtocolData(params, callback) {
    let allTrancheData = await getAllTrancheData(params);
    let protocolData = {
        tvl: ethers_1.BigNumber.from(0),
        totalReserves: ethers_1.BigNumber.from(0),
        totalSupplied: ethers_1.BigNumber.from(0),
        totalBorrowed: ethers_1.BigNumber.from(0),
        numLenders: 0,
        numBorrowers: 0,
        numTranches: allTrancheData.length,
        numMarkets: 0,
        topTranches: [],
        topSuppliedAssets: [],
        topBorrowedAssets: [],
    };
    allTrancheData.map((data) => {
        protocolData.tvl = protocolData.tvl.add(data.tvl);
        protocolData.totalReserves = protocolData.totalReserves.add(data.availableLiquidity);
        protocolData.totalSupplied = protocolData.totalSupplied.add(data.totalSupplied);
        protocolData.totalBorrowed = protocolData.totalBorrowed.add(data.totalBorrowed);
        protocolData.numMarkets += data.assets.length;
    });
    let topTranches = [...allTrancheData].sort((a, b) => {
        return a.totalSupplied
            .add(a.totalBorrowed)
            .gt(b.totalSupplied.add(b.totalBorrowed))
            ? -1
            : 1;
    });
    protocolData.topTranches = topTranches.slice(0, Math.min(5, topTranches.length));
    try {
        let topAssets = await getTopAssets(params);
        protocolData.topSuppliedAssets = topAssets.topSuppliedAssets;
        protocolData.topBorrowedAssets = topAssets.topBorrowedAssets;
    }
    catch (e) {
        console.log("UNABLE TO GET TOP SUPPLIED AND BORROWED DATA", e);
    }
    return protocolData;
}
exports.getProtocolData = getProtocolData;
async function getTopAssets(params, callback) {
    let data = await getAllMarketsData(params);
    console.log("done withe get all markets");
    let aggregatedSuppliedAssetData = {};
    let aggregatedBorrowedAssetData = {};
    data.map((assetData) => {
        let asset = assetData.asset.toString();
        if (asset in aggregatedSuppliedAssetData) {
            aggregatedSuppliedAssetData[asset].totalSupplied +=
                assetData.totalSupplied;
        }
        else {
            aggregatedSuppliedAssetData[asset] = {
                amount: assetData.totalSupplied,
                asset: asset,
            };
        }
        if (asset in aggregatedBorrowedAssetData) {
            aggregatedBorrowedAssetData[asset].amount = aggregatedBorrowedAssetData[asset].amount.add(assetData.totalBorrowed);
        }
        else {
            aggregatedBorrowedAssetData[asset] = {
                amount: assetData.totalBorrowed,
                asset: asset,
            };
        }
    });
    let supplied = Object.keys(aggregatedSuppliedAssetData).map(function (key) {
        return aggregatedSuppliedAssetData[key];
    });
    let borrowed = Object.keys(aggregatedBorrowedAssetData).map(function (key) {
        return aggregatedBorrowedAssetData[key];
    });
    supplied.sort(function (a, b) {
        return a.amount.gt(b.amount) ? -1 : 1;
    });
    borrowed.sort(function (a, b) {
        return a.amount.gt(b.amount) ? -1 : 1;
    });
    return {
        topSuppliedAssets: supplied,
        topBorrowedAssets: borrowed,
    };
}
exports.getTopAssets = getTopAssets;
/**
 * TRANCHE LEVEL ANALYTICS
 */
async function getTrancheMarketsData(params, callback) {
    const cacheKey = "markets-" + params.tranche;
    const cachedMarketsData = await utils_1.cache.getItem(cacheKey);
    if (cachedMarketsData) {
        // found in cache!
        console.log("CACHE HIT! for tranche", params.tranche);
        return cachedMarketsData;
    }
    // not in cache (expired)
    const provider = contract_getters_1.getProvider(params.providerRpc, params.test);
    const { abi, bytecode, } = require("./artifacts/contracts/analytics-utilities/asset/GetAllTrancheAssetsData.sol/GetAllTrancheAssetsData.json");
    let _addressProvider = constants_1.deployments.LendingPoolAddressesProvider[params.network || "mainnet"]
        .address;
    let [data] = await decode_bytecode_1.decodeConstructorBytecode(abi, bytecode, provider, [
        _addressProvider,
        params.tranche,
    ]);
    // ttl of 60 seconds
    console.log("NO CACHE HIT, SETTING CACHE for tranche", params.tranche);
    await utils_1.cache.setItem(cacheKey, data, { ttl: 60 });
    return data;
}
exports.getTrancheMarketsData = getTrancheMarketsData;
async function getAllTrancheData(params, callback) {
    const provider = contract_getters_1.getProvider(params.providerRpc, params.test);
    const { abi, bytecode, } = require("./artifacts/contracts/analytics-utilities/tranche/GetAllTrancheData.sol/GetAllTrancheData.json");
    let _addressProvider = constants_1.deployments.LendingPoolAddressesProvider[params.network || "mainnet"]
        .address;
    let [data] = await decode_bytecode_1.decodeConstructorBytecode(abi, bytecode, provider, [
        _addressProvider,
    ]);
    return data;
}
exports.getAllTrancheData = getAllTrancheData;
async function getTrancheData(params, callback) {
    const provider = contract_getters_1.getProvider(params.providerRpc, params.test);
    const { abi, bytecode, } = require("./artifacts/contracts/analytics-utilities/tranche/GetTrancheData.sol/GetTrancheData.json");
    let _addressProvider = constants_1.deployments.LendingPoolAddressesProvider[params.network || "mainnet"]
        .address;
    let [data] = await decode_bytecode_1.decodeConstructorBytecode(abi, bytecode, provider, [
        _addressProvider,
        params.tranche,
    ]);
    return data;
}
exports.getTrancheData = getTrancheData;
/**
 * ASSET LEVEL ANALYTICS
 */
async function getTrancheAssetData(params, callback) {
    const provider = contract_getters_1.getProvider(params.providerRpc, params.test);
    const { abi, bytecode, } = require("./artifacts/contracts/analytics-utilities/asset/GetTrancheAssetData.sol/GetTrancheAssetData.json");
    let _addressProvider = constants_1.deployments.LendingPoolAddressesProvider[params.network || "mainnet"]
        .address;
    let [data] = await decode_bytecode_1.decodeConstructorBytecode(abi, bytecode, provider, [
        _addressProvider,
        params.asset,
        params.tranche,
    ]);
    return data;
}
exports.getTrancheAssetData = getTrancheAssetData;
/**
 * USER LEVEL ANALYTICS
 */
async function getUserSummaryData(params, callback) {
    const provider = contract_getters_1.getProvider(params.providerRpc, params.test);
    const { abi, bytecode, } = require("./artifacts/contracts/analytics-utilities/user/GetUserSummaryData.sol/GetUserSummaryData.json");
    let _addressProvider = constants_1.deployments.LendingPoolAddressesProvider[params.network || "mainnet"]
        .address;
    let [data] = await decode_bytecode_1.decodeConstructorBytecode(abi, bytecode, provider, [
        _addressProvider,
        params.user,
    ]);
    return data;
}
exports.getUserSummaryData = getUserSummaryData;
async function getUserTrancheData(params, callback) {
    const provider = contract_getters_1.getProvider(params.providerRpc, params.test);
    const { abi, bytecode, } = require("./artifacts/contracts/analytics-utilities/user/GetUserTrancheData.sol/GetUserTrancheData.json");
    let _addressProvider = constants_1.deployments.LendingPoolAddressesProvider[params.network || "mainnet"]
        .address;
    let [data] = await decode_bytecode_1.decodeConstructorBytecode(abi, bytecode, provider, [
        _addressProvider,
        params.user,
        params.tranche,
    ]);
    return data;
}
exports.getUserTrancheData = getUserTrancheData;
async function getUserWalletData(params, callback) {
    const provider = contract_getters_1.getProvider(params.providerRpc, params.test);
    const { abi, bytecode, } = require("../contracts/artifacts/contracts/analytics-utilities/user/GetUserWalletData.sol/GetUserWalletData.json");
    let _addressProvider = constants_1.deployments.LendingPoolAddressesProvider[params.network || "mainnet"]
        .address;
    let [data] = await decode_bytecode_1.decodeConstructorBytecode(abi, bytecode, provider, [
        _addressProvider,
        params.user,
    ]);
    return data;
}
exports.getUserWalletData = getUserWalletData;
//# sourceMappingURL=analytics.js.map