"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateRealizedLpFeePct = exports.calculateApyFromUtilization = exports.calculateInstantaneousRate = exports.LPFeeCalculator = exports.truncate18DecimalBN = void 0;
var tslib_1 = require("tslib");
var decimal_js_1 = tslib_1.__importDefault(require("decimal.js"));
var utils_1 = require("../utils");
var ONE_HUNDRED_PERCENT = (0, utils_1.toBN)(10).pow(18);
function convertApyToWeeklyFee(apy) {
    var weeklyFeePct = decimal_js_1.default.pow(new decimal_js_1.default("1").plus((0, utils_1.fromWei)(apy)), new decimal_js_1.default("1").dividedBy(new decimal_js_1.default("52"))).minus(new decimal_js_1.default("1"));
    return (0, utils_1.toBN)(weeklyFeePct.times(utils_1.fixedPointAdjustment.toString()).floor().toString());
}
function truncate18DecimalBN(input, digits) {
    var digitsToDrop = 18 - digits;
    var multiplier = (0, utils_1.toBN)(10).pow(digitsToDrop);
    return input.div(multiplier).mul(multiplier);
}
exports.truncate18DecimalBN = truncate18DecimalBN;
var LPFeeCalculator = (function () {
    function LPFeeCalculator(rateModel) {
        this.rateModel = rateModel;
    }
    LPFeeCalculator.prototype.calculateAreaUnderRateCurve = function (utilization) {
        var utilizationBeforeKink = (0, utils_1.min)(utilization, this.rateModel.UBar);
        var rectangle1Area = utilizationBeforeKink.mul(this.rateModel.R0).div(utils_1.fixedPointAdjustment);
        var triangle1Area = (0, utils_1.toBNWei)("0.5")
            .mul(this.calculateInstantaneousRate(utilizationBeforeKink).sub(this.rateModel.R0))
            .mul(utilizationBeforeKink)
            .div(utils_1.fixedPointAdjustment)
            .div(utils_1.fixedPointAdjustment);
        var utilizationAfter = (0, utils_1.max)((0, utils_1.toBN)("0"), utilization.sub(this.rateModel.UBar));
        var rectangle2Area = utilizationAfter
            .mul((0, utils_1.toBN)(this.rateModel.R0).add(this.rateModel.R1))
            .div(utils_1.fixedPointAdjustment);
        var triangle2Area = (0, utils_1.toBNWei)("0.5")
            .mul(this.calculateInstantaneousRate(utilization).sub((0, utils_1.toBN)(this.rateModel.R0).add(this.rateModel.R1)))
            .mul(utilizationAfter)
            .div(utils_1.fixedPointAdjustment)
            .div(utils_1.fixedPointAdjustment);
        return rectangle1Area.add(triangle1Area).add(rectangle2Area).add(triangle2Area);
    };
    LPFeeCalculator.prototype.calculateInstantaneousRate = function (utilization) {
        var beforeKink = this.rateModel.UBar.toString() === "0"
            ? (0, utils_1.toBN)(0)
            : (0, utils_1.min)(utilization, this.rateModel.UBar).mul(this.rateModel.R1).div(this.rateModel.UBar);
        var afterKink = (0, utils_1.max)((0, utils_1.toBN)("0"), (0, utils_1.toBN)(utilization).sub(this.rateModel.UBar))
            .mul(this.rateModel.R2)
            .div((0, utils_1.toBNWei)("1").sub(this.rateModel.UBar));
        return (0, utils_1.toBN)(this.rateModel.R0).add(beforeKink).add(afterKink);
    };
    LPFeeCalculator.prototype.calculateRealizedLpFeePct = function (utilizationBeforeDeposit, utilizationAfterDeposit, truncateDecimals) {
        if (truncateDecimals === void 0) { truncateDecimals = false; }
        var apy = this.calculateApyFromUtilization((0, utils_1.toBN)(utilizationBeforeDeposit), (0, utils_1.toBN)(utilizationAfterDeposit));
        return (0, utils_1.min)(ONE_HUNDRED_PERCENT, truncateDecimals ? truncate18DecimalBN(convertApyToWeeklyFee(apy), 6) : convertApyToWeeklyFee(apy));
    };
    LPFeeCalculator.prototype.calculateApyFromUtilization = function (utilizationBeforeDeposit, utilizationAfterDeposit) {
        if (utilizationBeforeDeposit.eq(utilizationAfterDeposit))
            return this.calculateInstantaneousRate(utilizationBeforeDeposit);
        var areaBeforeDeposit = this.calculateAreaUnderRateCurve(utilizationBeforeDeposit);
        var areaAfterDeposit = this.calculateAreaUnderRateCurve(utilizationAfterDeposit);
        var numerator = areaAfterDeposit.sub(areaBeforeDeposit);
        var denominator = utilizationAfterDeposit.sub(utilizationBeforeDeposit);
        return numerator.mul(utils_1.fixedPointAdjustment).div(denominator);
    };
    return LPFeeCalculator;
}());
exports.LPFeeCalculator = LPFeeCalculator;
function calculateInstantaneousRate(rateModel, utilization) {
    return new LPFeeCalculator(rateModel).calculateInstantaneousRate(utilization);
}
exports.calculateInstantaneousRate = calculateInstantaneousRate;
function calculateApyFromUtilization(rateModel, utilizationBeforeDeposit, utilizationAfterDeposit) {
    return new LPFeeCalculator(rateModel).calculateApyFromUtilization(utilizationBeforeDeposit, utilizationAfterDeposit);
}
exports.calculateApyFromUtilization = calculateApyFromUtilization;
function calculateRealizedLpFeePct(rateModel, utilizationBeforeDeposit, utilizationAfterDeposit, truncateDecimals) {
    if (truncateDecimals === void 0) { truncateDecimals = false; }
    return new LPFeeCalculator(rateModel).calculateRealizedLpFeePct(utilizationBeforeDeposit, utilizationAfterDeposit, truncateDecimals);
}
exports.calculateRealizedLpFeePct = calculateRealizedLpFeePct;
//# sourceMappingURL=lpFeeCalculator.js.map