"use strict";
/**
 * @file Price Feed
 * @desc These methods facilitate interactions with the Open Price Feed smart
 *     contracts.
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPrice = void 0;
const eth = __importStar(require("./eth"));
const helpers_1 = require("./helpers");
const constants_1 = require("./constants");
function validateAsset(asset, argument, errorPrefix) {
    if (typeof asset !== 'string' || asset.length < 1) {
        throw Error(errorPrefix + 'Argument `' + argument + '` must be a non-empty string.');
    }
    const assetIsCToken = asset.includes('sdr');
    const cTokenName = assetIsCToken ? asset : 'sdr' + asset;
    const cTokenAddress = (0, constants_1.getAddress)(this._network.name, cTokenName);
    let underlyingName = assetIsCToken ? asset.slice(1, asset.length) : asset;
    const underlyingAddress = (0, constants_1.getAddress)(this._network.name, underlyingName);
    if (!(0, constants_1.isCTokenAllowed)(this._network.name, cTokenName) || !(0, constants_1.isUnderlyAllowed)(this._network.name, underlyingName)) {
        throw Error(errorPrefix + 'Argument `' + argument + '` is not supported.');
    }
    const underlyingDecimals = (0, constants_1.getDecimals)(this._network.name, underlyingName);
    if (underlyingDecimals <= 0) {
        throw Error(`Asset ${asset} decimals is configured wrong as ${underlyingDecimals} `);
    }
    // The open price feed reveals BTC, not WBTC.
    underlyingName = underlyingName === 'WBTC' ? 'BTC' : underlyingName;
    return [assetIsCToken, cTokenName, cTokenAddress, underlyingName, underlyingAddress, underlyingDecimals];
}
async function cTokenExchangeRate(cTokenAddress, cTokenName, underlyingDecimals) {
    const address = cTokenAddress;
    const method = 'exchangeRateCurrent';
    const options = {
        _compoundProvider: this._provider,
        abi: (0, constants_1.isEther)(this._network.name, cTokenName) ? constants_1.abi.cEther : constants_1.abi.cErc20,
    };
    const exchangeRateCurrent = await eth.read(address, method, [], options);
    const mantissa = 18 + underlyingDecimals - 8; // cToken always 8 decimals
    const oneCTokenInUnderlying = exchangeRateCurrent / Math.pow(10, mantissa);
    return oneCTokenInUnderlying;
}
/**
 * Gets an asset's price from the Compound Protocol open price feed. The price
 *    of the asset can be returned in any other supported asset value, including
 *    all cTokens and underlyings.
 *
 * @param {string} asset A string of a supported asset in which to find the
 *     current price.
 * @param {string} [inAsset] A string of a supported asset in which to express
 *     the `asset` parameter's price. This defaults to USD.
 *
 * @returns {string} Returns a string of the numeric value of the asset.
 *
 * @example
 * ```
 * const compound = new Compound(window.ethereum);
 * let price;
 *
 * (async function () {
 *
 *   price = await compound.getPrice(Compound.WBTC);
 *   console.log('WBTC in USD', price); // 6 decimals, see Open Price Feed docs
 *
 *   price = await compound.getPrice(Compound.BAT, Compound.USDC); // supports cTokens too
 *   console.log('BAT in USDC', price);
 *
 * })().catch(console.error);
 * ```
 */
async function getPrice(asset, inAsset) {
    await (0, helpers_1.netId)(this);
    const errorPrefix = 'Compound [getPrice] | ';
    const [
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    assetIsCToken, cTokenName, cTokenAddress, underlyingName, underlyingAddress, underlyingDecimals,] = validateAsset.bind(this)(asset, 'asset', errorPrefix);
    const [
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    inAssetIsCToken, inAssetCTokenName, inAssetCTokenAddress, inAssetUnderlyingName, inAssetUnderlyingAddress, inAssetUnderlyingDecimals,] = validateAsset.bind(this)(inAsset, 'inAsset', errorPrefix);
    const priceFeedAddress = (0, constants_1.getAddress)(this._network.name, 'PriceFeed');
    const trxOptions = {
        _compoundProvider: this._provider,
        abi: constants_1.abi.PriceFeed,
    };
    const assetUnderlyingPrice = await eth.read(priceFeedAddress, 'price', [underlyingName], trxOptions);
    const inAssetUnderlyingPrice = await eth.read(priceFeedAddress, 'price', [inAssetUnderlyingName], trxOptions);
    let assetCTokensInUnderlying, inAssetCTokensInUnderlying;
    if (assetIsCToken) {
        assetCTokensInUnderlying = await cTokenExchangeRate.bind(this)(cTokenAddress, cTokenName, underlyingDecimals);
    }
    if (inAssetIsCToken) {
        inAssetCTokensInUnderlying = await cTokenExchangeRate.bind(this)(inAssetCTokenAddress, inAssetCTokenName, inAssetUnderlyingDecimals);
    }
    let result;
    if (!assetIsCToken && !inAssetIsCToken) {
        result = assetUnderlyingPrice / inAssetUnderlyingPrice;
    }
    else if (assetIsCToken && !inAssetIsCToken) {
        const assetInOther = assetUnderlyingPrice / inAssetUnderlyingPrice;
        result = assetInOther * assetCTokensInUnderlying;
    }
    else if (!assetIsCToken && inAssetIsCToken) {
        const assetInOther = assetUnderlyingPrice / inAssetUnderlyingPrice;
        result = assetInOther / inAssetCTokensInUnderlying;
    }
    else {
        const assetInOther = assetUnderlyingPrice / inAssetUnderlyingPrice;
        const cTokensInUnderlying = assetInOther / assetCTokensInUnderlying;
        result = inAssetCTokensInUnderlying * cTokensInUnderlying;
    }
    return result;
}
exports.getPrice = getPrice;
//# sourceMappingURL=priceFeed.js.map