"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.VaultExt = exports.VaultStatusExt = void 0;
const utils_1 = require("../utils");
const currency_1 = require("./currency");
var VaultStatusExt;
(function (VaultStatusExt) {
    VaultStatusExt[VaultStatusExt["Active"] = 0] = "Active";
    VaultStatusExt[VaultStatusExt["Inactive"] = 1] = "Inactive";
    VaultStatusExt[VaultStatusExt["Liquidated"] = 2] = "Liquidated";
    VaultStatusExt[VaultStatusExt["CommittedTheft"] = 3] = "CommittedTheft";
})(VaultStatusExt = exports.VaultStatusExt || (exports.VaultStatusExt = {}));
class VaultExt {
    constructor(api, oracleAPI, systemAPI, wallet, backingCollateral, id, status, bannedUntil, toBeIssuedTokens, issuedTokens, toBeRedeemedTokens, toBeReplacedTokens, replaceCollateral, liquidatedCollateral) {
        this.api = api;
        this.oracleAPI = oracleAPI;
        this.systemAPI = systemAPI;
        this.wallet = wallet;
        this.backingCollateral = backingCollateral;
        this.id = id;
        this.status = status;
        this.bannedUntil = bannedUntil;
        this.toBeIssuedTokens = toBeIssuedTokens;
        this.issuedTokens = issuedTokens;
        this.toBeRedeemedTokens = toBeRedeemedTokens;
        this.toBeReplacedTokens = toBeReplacedTokens;
        this.replaceCollateral = replaceCollateral;
        this.liquidatedCollateral = liquidatedCollateral;
    }
    getRedeemableTokens() {
        return this.issuedTokens.sub(this.toBeRedeemedTokens);
    }
    getIssuableTokens() {
        return __awaiter(this, void 0, void 0, function* () {
            const isBanned = yield this.isBanned();
            if (isBanned) {
                return (0, utils_1.newMonetaryAmount)(0, (0, currency_1.currencyIdToMonetaryCurrency)(this.id.currencies.wrapped));
            }
            const freeCollateral = yield this.getFreeCollateral();
            const secureCollateralThreshold = yield this.getSecureCollateralThreshold();
            const backableWrappedTokens = yield this.oracleAPI.convertCollateralToWrapped(freeCollateral);
            // Force type-assert here as the oracle API only uses wrapped Bitcoin
            return backableWrappedTokens.div(secureCollateralThreshold);
        });
    }
    isBanned() {
        return __awaiter(this, void 0, void 0, function* () {
            const currentBlockNumber = yield this.systemAPI.getCurrentActiveBlockNumber();
            if (!this.bannedUntil) {
                return false;
            }
            return this.bannedUntil >= currentBlockNumber;
        });
    }
    getBackedTokens() {
        return this.issuedTokens.add(this.toBeIssuedTokens);
    }
    getFreeCollateral() {
        return __awaiter(this, void 0, void 0, function* () {
            const usedCollateral = yield this.getUsedCollateral();
            const totalCollateral = yield this.computeBackingCollateral();
            return totalCollateral.sub(usedCollateral);
        });
    }
    getUsedCollateral() {
        return __awaiter(this, void 0, void 0, function* () {
            const backedTokens = this.getBackedTokens();
            const backedTokensInCollateral = yield this.oracleAPI.convertWrappedToCurrency(
            // Force type-assert here as the oracle API only uses wrapped Bitcoin
            backedTokens, (0, currency_1.currencyIdToMonetaryCurrency)(this.id.currencies.collateral));
            const secureCollateralThreshold = yield this.getSecureCollateralThreshold();
            const usedCollateral = backedTokensInCollateral.mul(secureCollateralThreshold);
            const totalCollateral = yield this.computeBackingCollateral();
            return totalCollateral.min(usedCollateral);
        });
    }
    // TODO: The functions below are duplicated from other APIs. Remove them after APIs
    // are refactored to the builder pattern
    getSecureCollateralThreshold() {
        return __awaiter(this, void 0, void 0, function* () {
            const threshold = yield this.api.query.vaultRegistry.secureCollateralThreshold(this.id.currencies);
            return (0, utils_1.decodeFixedPointType)(threshold.value);
        });
    }
    computeBackingCollateral(nonce) {
        return __awaiter(this, void 0, void 0, function* () {
            if (nonce === undefined) {
                nonce = yield this.getStakingPoolNonce();
            }
            const rawBackingCollateral = yield this.api.query.vaultStaking.totalCurrentStake(nonce, this.id);
            const collateralCurrency = (0, currency_1.currencyIdToMonetaryCurrency)(this.id.currencies.collateral);
            return (0, utils_1.newMonetaryAmount)((0, utils_1.decodeFixedPointType)(rawBackingCollateral), collateralCurrency);
        });
    }
    getStakingPoolNonce() {
        return __awaiter(this, void 0, void 0, function* () {
            const rawNonce = yield this.api.query.vaultStaking.nonce(this.id);
            return rawNonce.toNumber();
        });
    }
}
exports.VaultExt = VaultExt;
//# sourceMappingURL=vault.js.map