import { __awaiter, __generator } from "tslib";
import Decimal from "decimal.js";
import bs58 from "bs58";
import { ethers } from "ethers";
import { BigNumber, formatUnits, parseUnits, toBN } from "./BigNumberUtils";
import { ConvertDecimals } from "./FormattingUtils";
export var AddressZero = ethers.constants.AddressZero;
export var MAX_BIG_INT = BigNumber.from(Number.MAX_SAFE_INTEGER.toString());
export var keccak256 = ethers.utils.keccak256;
export { bs58 };
/**
 * toBNWei.
 *
 * @param {BigNumberish} num
 * @param {number} decimals
 * @returns {BN}
 */
export var toBNWei = function (num, decimals) { return parseUnits(num.toString(), decimals); };
/**
 * fromWei.
 *
 * @param {BigNumberish} num
 * @param {number} decimals
 * @returns {string}
 */
export var fromWei = function (num, decimals) { return formatUnits(num.toString(), decimals); };
/**
 * min.
 *
 * @param {BigNumberish} a
 * @param {BigNumberish} b
 * @returns {BN}
 */
export function min(a, b) {
    var bna = toBN(a);
    var bnb = toBN(b);
    return bna.lte(bnb) ? bna : bnb;
}
/**
 * max.
 *
 * @param {BigNumberish} a
 * @param {BigNumberish} b
 * @returns {BN}
 */
export function max(a, b) {
    var bna = toBN(a);
    var bnb = toBN(b);
    return bna.gte(bnb) ? bna : bnb;
}
export var fixedPointAdjustment = toBNWei("1");
/**
 * Convert an amount of native gas token into a token given price and token decimals.
 *
 * @param {BigNumberish} fromAmount - Amount of native gas token to convert.
 * @param {string | number} [ price=1 ] - The price as native gas token per token, ie how much native gas token can 1 token buy.
 * @param {} [ toDecimals=18 ] - Number of decimals for the token currency.
 * @param {} [ nativeDecimals=18 ] - Number of decimals for the native token currency.
 * @returns {string} The number of tokens denominated in token decimals in the smallest unit (wei).
 */
export function nativeToToken(fromAmount, price, toDecimals, nativeDecimals) {
    if (price === void 0) { price = 1; }
    if (toDecimals === void 0) { toDecimals = 18; }
    if (nativeDecimals === void 0) { nativeDecimals = 18; }
    var priceWei = toBNWei(price);
    var toAmount = toBNWei(fromAmount).div(priceWei);
    return ConvertDecimals(nativeDecimals, toDecimals)(toAmount).toString();
}
/**
 * Convert a gas amount and gas price to wei.
 *
 * @param {number} gas - gas amount.
 * @param {BigNumberish} gasPrice - gas price in gwei.
 * @returns {BigNumber} - total fees in wei.
 */
export var gasCost = function (gas, gasPrice) {
    return BigNumber.from(gas).mul(gasPrice);
};
/**
 * getGasFees. Low level pure function call to calculate gas fees.
 *
 * @param {number} gas - The gast cost for transfer, use constants defined in file.
 * @param {BigNumberish} gasPrice - Estimated gas price in wei.
 * @param {string | number} [price = 1] - The price of the token in native gas token, how much native gas token can 1 token buy.
 * @param {number} [decimals=18] - Number of decimals of token.
 * @returns {string} - The value of fees native to the token provided, in its smallest unit.
 */
export function calculateGasFees(gas, gasPrice, price, decimals) {
    if (price === void 0) { price = 1; }
    if (decimals === void 0) { decimals = 18; }
    var amountNative = gasCost(gas, gasPrice);
    return nativeToToken(amountNative, price, decimals);
}
/**
 * percent.
 *
 * @param {BigNumberish} numerator
 * @param {BigNumberish} denominator
 * @returns {BN}
 */
export function percent(numerator, denominator) {
    return fixedPointAdjustment.mul(numerator).div(denominator);
}
/**
 * calcContinuousCompoundInterest. From https://www.calculatorsoup.com/calculators/financial/compound-interest-calculator.php?given_data=find_r&A=2&P=1&n=0&t=1&given_data_last=find_r&action=solve
 * Returns a yearly interest rate if start/end amount had been continuously compounded over the period elapsed. Multiply result by 100 for a %.
 *
 * @param {string} startAmount
 * @param {string} endAmount
 * @param {string} periodsElapsed
 * @param {string} periodsPerYear
 */
export var calcContinuousCompoundInterest = function (startAmount, endAmount, periodsElapsed, periodsPerYear) {
    var years = new Decimal(periodsPerYear).div(periodsElapsed);
    return new Decimal(endAmount).div(startAmount).ln().div(years).toString();
};
/**
 * calcPeriodicCompoundInterest. Taken from https://www.calculatorsoup.com/calculators/financial/compound-interest-calculator.php?given_data=find_r&A=2&P=1&n=365&t=1&given_data_last=find_r&action=solve
 * This will return a periodically compounded interest rate for 1 year. Multiply result by 100 for a %.
 *
 * @param {string} startAmount - Starting amount or price
 * @param {string} endAmount - Ending amount or price
 * @param {string} periodsElapsed - How many periods elapsed for the start and end amount.
 * @param {string} periodsPerYear - How many periods in 1 year.
 */
export var calcPeriodicCompoundInterest = function (startAmount, endAmount, periodsElapsed, periodsPerYear) {
    var n = new Decimal(periodsPerYear);
    var A = new Decimal(endAmount);
    var P = new Decimal(startAmount);
    var t = new Decimal(periodsPerYear).div(periodsElapsed);
    var one = new Decimal(1);
    return n
        .mul(A.div(P)
        .pow(one.div(n.div(t)))
        .sub(one))
        .toFixed(18);
};
/**
 * calcApr. Simple apr calculation based on extrapolating the difference for a short period over a year.
 *
 * @param {Decimalish} startAmount - Starting amount or price
 * @param {Decimalish} endAmount - Ending amount or price
 * @param {Decimalish} periodsElapsed - periods elapsed from start to end
 * @param {Decimalish} periodsPerYear - periods per year
 */
export var calcApr = function (startAmount, endAmount, periodsElapsed, periodsPerYear) {
    return new Decimal(endAmount).sub(startAmount).div(startAmount).mul(periodsPerYear).div(periodsElapsed).toFixed(18);
};
/**
 * Takes two values and returns a list of number intervals
 *
 * @example
 * ```js
 * getSamplesBetween(1, 9, 3) //returns [[1, 3], [4, 7], [8, 9]]
 * ```
 */
export var getSamplesBetween = function (min, max, size) {
    var keepIterate = true;
    var intervals = [];
    while (keepIterate) {
        var to = Math.min(min + size - 1, max);
        intervals.push([min, to]);
        min = to + 1;
        if (min >= max)
            keepIterate = false;
    }
    return intervals;
};
/**
 * A promise that resolves after a specified number of seconds
 * @param seconds The number of seconds to wait
 */
export function delay(seconds) {
    return new Promise(function (resolve) { return setTimeout(resolve, seconds * 1000); });
}
/**
 * Attempt to retry a function call a number of times with a delay between each attempt
 * @param call The function to call
 * @param times The number of times to retry
 * @param delayS The number of seconds to delay between each attempt
 * @returns The result of the function call.
 */
export function retry(call, times, delayS) {
    var _this = this;
    var promiseChain = call();
    for (var i = 0; i < times; i++)
        promiseChain = promiseChain.catch(function () { return __awaiter(_this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, delay(delayS)];
                    case 1:
                        _a.sent();
                        return [4 /*yield*/, call()];
                    case 2: return [2 /*return*/, _a.sent()];
                }
            });
        }); });
    return promiseChain;
}
export function randomAddress() {
    return ethers.utils.getAddress(ethers.utils.hexlify(ethers.utils.randomBytes(20)));
}
//# sourceMappingURL=common.js.map