"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.DefaultVaultsAPI = void 0;
const utils_1 = require("../utils");
const types_1 = require("../types");
class DefaultVaultsAPI {
    constructor(api, btcNetwork, electrsAPI, wrappedCurrency, governanceCurrency, tokensAPI, oracleAPI, feeAPI, rewardsAPI, systemAPI, transactionAPI) {
        this.api = api;
        this.btcNetwork = btcNetwork;
        this.electrsAPI = electrsAPI;
        this.wrappedCurrency = wrappedCurrency;
        this.governanceCurrency = governanceCurrency;
        this.tokensAPI = tokensAPI;
        this.oracleAPI = oracleAPI;
        this.feeAPI = feeAPI;
        this.rewardsAPI = rewardsAPI;
        this.systemAPI = systemAPI;
        this.transactionAPI = transactionAPI;
    }
    getWrappedCurrency() {
        return this.wrappedCurrency;
    }
    register(amount, publicKey) {
        return __awaiter(this, void 0, void 0, function* () {
            const amountAtomicUnit = this.api.createType("Balance", amount.toString());
            const currencyPair = (0, utils_1.newVaultCurrencyPair)(this.api, (0, types_1.tickerToMonetaryCurrency)(this.api, amount.currency.ticker), this.wrappedCurrency);
            yield Promise.all([
                this.transactionAPI.sendLogged(this.api.tx.vaultRegistry.registerPublicKey(publicKey), this.api.events.vaultRegistry.UpdatePublicKey, true),
                this.transactionAPI.sendLogged(this.api.tx.vaultRegistry.registerVault(currencyPair, amountAtomicUnit), this.api.events.vaultRegistry.RegisterVault, true),
            ]);
        });
    }
    withdrawCollateral(amount) {
        return __awaiter(this, void 0, void 0, function* () {
            const amountAtomicUnit = this.api.createType("Balance", amount.toString());
            const currencyPair = (0, utils_1.newVaultCurrencyPair)(this.api, (0, types_1.tickerToMonetaryCurrency)(this.api, amount.currency.ticker), this.wrappedCurrency);
            const tx = this.api.tx.vaultRegistry.withdrawCollateral(currencyPair, amountAtomicUnit);
            yield this.transactionAPI.sendLogged(tx, this.api.events.vaultRegistry.WithdrawCollateral, true);
        });
    }
    depositCollateral(amount) {
        return __awaiter(this, void 0, void 0, function* () {
            const amountAsPlanck = this.api.createType("Balance", amount.toString());
            const currencyPair = (0, utils_1.newVaultCurrencyPair)(this.api, (0, types_1.tickerToMonetaryCurrency)(this.api, amount.currency.ticker), this.wrappedCurrency);
            const tx = this.api.tx.vaultRegistry.depositCollateral(currencyPair, amountAsPlanck);
            yield this.transactionAPI.sendLogged(tx, this.api.events.vaultRegistry.DepositCollateral, true);
        });
    }
    list(atBlock) {
        return __awaiter(this, void 0, void 0, function* () {
            const vaultsMap = yield (atBlock
                ? this.api.query.vaultRegistry.vaults.entriesAt(atBlock)
                : this.api.query.vaultRegistry.vaults.entries());
            return Promise.all(vaultsMap
                .filter((v) => v[1].isSome)
                .map((v) => this.parseVault(v[1].value, this.btcNetwork)));
        });
    }
    get(vaultAccountId, collateralCurrencyIdLiteral) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                const collateralCurrency = (0, types_1.currencyIdLiteralToMonetaryCurrency)(this.api, collateralCurrencyIdLiteral);
                const vaultId = (0, utils_1.newVaultId)(this.api, vaultAccountId.toString(), collateralCurrency, this.wrappedCurrency);
                const vault = yield this.api.query.vaultRegistry.vaults(vaultId);
                if (!vault.isSome) {
                    return Promise.reject(`No vault registered with id ${vaultId}`);
                }
                return this.parseVault(vault.value, this.btcNetwork);
            }
            catch (error) {
                return Promise.reject(error);
            }
        });
    }
    getCollateral(vaultAccountId, collateralCurrencyIdLiteral) {
        return __awaiter(this, void 0, void 0, function* () {
            const collateralCurrency = (0, types_1.currencyIdLiteralToMonetaryCurrency)(this.api, collateralCurrencyIdLiteral);
            return this.rewardsAPI.computeCollateralInStakingPool((0, utils_1.newVaultId)(this.api, vaultAccountId.toString(), collateralCurrency, this.wrappedCurrency), vaultAccountId);
        });
    }
    getMaxNominationRatio(collateralCurrency) {
        return __awaiter(this, void 0, void 0, function* () {
            const [premiumRedeemThreshold, secureCollateralThreshold] = yield Promise.all([
                this.getPremiumRedeemThreshold(collateralCurrency),
                this.getSecureCollateralThreshold(collateralCurrency),
            ]);
            return secureCollateralThreshold.div(premiumRedeemThreshold);
        });
    }
    computeBackingCollateral(vaultId, nonce) {
        return __awaiter(this, void 0, void 0, function* () {
            const collateralCurrencyIdLiteral = (0, types_1.currencyIdToLiteral)(vaultId.currencies.collateral);
            if (nonce === undefined) {
                nonce = yield this.rewardsAPI.getStakingPoolNonce(collateralCurrencyIdLiteral, vaultId.accountId);
            }
            const rawBackingCollateral = yield this.api.query.vaultStaking.totalCurrentStake(nonce, vaultId);
            const collateralCurrency = (0, types_1.currencyIdToMonetaryCurrency)(vaultId.currencies.collateral);
            return (0, utils_1.newMonetaryAmount)((0, utils_1.decodeFixedPointType)(rawBackingCollateral), collateralCurrency);
        });
    }
    backingCollateralProportion(vaultAccountId, nominatorId, collateralCurrencyIdLiteral) {
        return __awaiter(this, void 0, void 0, function* () {
            const vault = yield this.get(vaultAccountId, collateralCurrencyIdLiteral);
            const collateralCurrency = (0, types_1.currencyIdLiteralToMonetaryCurrency)(this.api, collateralCurrencyIdLiteral);
            const nominatorCollateral = yield this.rewardsAPI.computeCollateralInStakingPool((0, utils_1.newVaultId)(this.api, vaultAccountId.toString(), collateralCurrency, this.wrappedCurrency), nominatorId);
            return nominatorCollateral.toBig().div(vault.backingCollateral.toBig());
        });
    }
    getBlockRewardAPY(vaultAccountId, nominatorId, collateralCurrency, governanceCurrency) {
        return __awaiter(this, void 0, void 0, function* () {
            const vault = yield this.get(vaultAccountId, collateralCurrency);
            const [globalRewardPerBlock, globalStake, vaultStake, vaultRewardShare, lockedCollateral, minimumBlockPeriod] = yield Promise.all([
                this.rewardsAPI.getRewardPerBlock(governanceCurrency),
                this.getTotalIssuedAmount(),
                this.getIssuedAmount(vaultAccountId, collateralCurrency),
                this.backingCollateralProportion(vaultAccountId, nominatorId, collateralCurrency),
                (yield this.tokensAPI.balance((0, types_1.currencyIdToMonetaryCurrency)(vault.id.currencies.collateral), vaultAccountId)).reserved,
                this.api.consts.timestamp.minimumPeriod,
            ]);
            if (globalStake.toBig().eq(0)) {
                return Promise.reject(new Error("No issued kBTC"));
            }
            const globalRewardShare = vaultStake.toBig().div(globalStake.toBig());
            const vaultRewardPerBlock = globalRewardPerBlock.mul(globalRewardShare);
            const ownRewardPerBlock = vaultRewardPerBlock.mul(vaultRewardShare);
            const rewardAsWrapped = yield this.oracleAPI.convertCollateralToWrapped(ownRewardPerBlock);
            const blockTime = minimumBlockPeriod.toNumber() * 2; // ms
            const blocksPerYear = (86400 * 365 * 1000) / blockTime;
            const annualisedReward = rewardAsWrapped.mul(blocksPerYear);
            return this.feeAPI.calculateAPY(annualisedReward, lockedCollateral);
        });
    }
    computeReward(vaultAccountId, nominatorId, collateralCurrencyId, rewardCurrencyIdLiteral, nonce) {
        return __awaiter(this, void 0, void 0, function* () {
            const [totalGlobalReward, globalRewardShare] = yield Promise.all([
                this.rewardsAPI.computeRewardInRewardsPool(rewardCurrencyIdLiteral, collateralCurrencyId, vaultAccountId),
                this.backingCollateralProportion(vaultAccountId, nominatorId, collateralCurrencyId),
            ]);
            const ownGlobalReward = totalGlobalReward.mul(globalRewardShare);
            const localReward = yield this.rewardsAPI.computeRewardInStakingPool(vaultAccountId, nominatorId, collateralCurrencyId, rewardCurrencyIdLiteral, nonce);
            return ownGlobalReward.add(localReward);
        });
    }
    getWrappedReward(vaultAccountId, collateralCurrency) {
        return __awaiter(this, void 0, void 0, function* () {
            return (yield this.computeReward(vaultAccountId, vaultAccountId, collateralCurrency, (0, types_1.tickerToCurrencyIdLiteral)(this.wrappedCurrency.ticker)));
        });
    }
    getGovernanceReward(vaultAccountId, vaultCollateralIdLiteral, governanceCurrencyIdLiteral) {
        return __awaiter(this, void 0, void 0, function* () {
            return (yield this.computeReward(vaultAccountId, vaultAccountId, vaultCollateralIdLiteral, governanceCurrencyIdLiteral));
        });
    }
    getStakingCapacity(vaultAccountId, collateralCurrency) {
        return __awaiter(this, void 0, void 0, function* () {
            const vault = yield this.get(vaultAccountId, collateralCurrency);
            const [collateral, maxNominationRatio] = yield Promise.all([
                this.getCollateral(vaultAccountId, collateralCurrency),
                this.getMaxNominationRatio((0, types_1.currencyIdToMonetaryCurrency)(vault.id.currencies.collateral)),
            ]);
            return collateral.mul(maxNominationRatio).sub(vault.backingCollateral);
        });
    }
    getLiquidationVault(collateralCurrency) {
        return __awaiter(this, void 0, void 0, function* () {
            const vaultCurrencyPair = (0, utils_1.newVaultCurrencyPair)(this.api, collateralCurrency, this.wrappedCurrency);
            const liquidationVault = yield this.api.query.vaultRegistry.liquidationVault(vaultCurrencyPair);
            if (!liquidationVault.isSome) {
                return Promise.reject("System vault could not be fetched");
            }
            return (0, utils_1.parseSystemVault)(liquidationVault.value, this.wrappedCurrency, collateralCurrency);
        });
    }
    isNoTokensIssuedError(e) {
        return e !== undefined && e.includes("No tokens issued");
    }
    isBelowPremiumThreshold(vaultId) {
        return __awaiter(this, void 0, void 0, function* () {
            const [premiumRedeemThreshold, vaultCollateralization] = yield Promise.all([
                this.getPremiumRedeemThreshold((0, types_1.currencyIdToMonetaryCurrency)(vaultId.currencies.collateral)),
                this.getCollateralizationFromVault(vaultId),
            ]);
            return vaultCollateralization.lt(premiumRedeemThreshold);
        });
    }
    getVaultCollateralization(vaultAccountId, collateralCurrencyIdLiteral, newCollateral, onlyIssued = false) {
        return __awaiter(this, void 0, void 0, function* () {
            let collateralization = undefined;
            const collateralCurrencyId = (0, utils_1.newCurrencyId)(this.api, collateralCurrencyIdLiteral);
            const vaultId = (0, utils_1.newVaultId)(this.api, vaultAccountId.toString(), (0, types_1.currencyIdToMonetaryCurrency)(collateralCurrencyId), this.wrappedCurrency);
            try {
                if (newCollateral) {
                    collateralization = yield this.getCollateralizationFromVaultAndCollateral(vaultId, newCollateral, onlyIssued);
                }
                else {
                    collateralization = yield this.getCollateralizationFromVault(vaultId, onlyIssued);
                }
            }
            catch (e) {
                if (this.isNoTokensIssuedError(e)) {
                    return Promise.resolve(undefined);
                }
                return Promise.reject(new Error(`Error during collateralization computation: ${(e)}`));
            }
            if (!collateralization) {
                return Promise.resolve(undefined);
            }
            return collateralization;
        });
    }
    getCollateralizationFromVault(vaultId, onlyIssued = false) {
        return __awaiter(this, void 0, void 0, function* () {
            const collateral = yield this.computeBackingCollateral(vaultId);
            return this.getCollateralizationFromVaultAndCollateral(vaultId, collateral, onlyIssued);
        });
    }
    getCollateralizationFromVaultAndCollateral(vaultId, newCollateral, onlyIssued) {
        return __awaiter(this, void 0, void 0, function* () {
            const vault = yield this.get(vaultId.accountId, (0, types_1.currencyIdToLiteral)(vaultId.currencies.collateral));
            const issuedTokens = yield (onlyIssued ? Promise.resolve(vault.issuedTokens) : vault.getBackedTokens());
            if (issuedTokens.isZero()) {
                return Promise.reject("No tokens issued");
            }
            const collateralInWrapped = yield this.oracleAPI.convertCollateralToWrapped(newCollateral);
            return collateralInWrapped.toBig().div(issuedTokens.toBig());
        });
    }
    getSystemCollateralization() {
        return __awaiter(this, void 0, void 0, function* () {
            // TODO: Implement once method of calculation is decided on
            return Promise.resolve(undefined);
        });
    }
    getRequiredCollateralForVault(vaultAccountId, currency) {
        return __awaiter(this, void 0, void 0, function* () {
            const vault = yield this.get(vaultAccountId, (0, types_1.tickerToCurrencyIdLiteral)(currency.ticker));
            const issuedTokens = vault.getBackedTokens();
            return yield this.getRequiredCollateralForWrapped(issuedTokens, currency);
        });
    }
    getRequiredCollateralForWrapped(wrappedAmount, currency) {
        return __awaiter(this, void 0, void 0, function* () {
            const secureCollateralThreshold = yield this.getSecureCollateralThreshold(currency);
            const requiredCollateralInWrappedCurrency = wrappedAmount.mul(secureCollateralThreshold);
            return yield this.oracleAPI.convertWrappedToCurrency(requiredCollateralInWrappedCurrency, currency);
        });
    }
    getIssuedAmount(vaultAccountId, collateralCurrency) {
        return __awaiter(this, void 0, void 0, function* () {
            const vault = yield this.get(vaultAccountId, collateralCurrency);
            return vault.issuedTokens;
        });
    }
    getTotalIssuedAmount() {
        return __awaiter(this, void 0, void 0, function* () {
            const issuedTokens = yield this.tokensAPI.total(this.wrappedCurrency);
            return issuedTokens;
        });
    }
    getTotalIssuableAmount() {
        return __awaiter(this, void 0, void 0, function* () {
            // get [[wrapped, collateral], amount][] map
            const perCurrencyPairCollateralAmounts = yield this.api.query.vaultRegistry.totalUserVaultCollateral.entries();
            // filter for wrapped === this.wrapped, as only one wrapped currency is handled at a time currently
            const perWrappedCurrencyCollateralAmounts = perCurrencyPairCollateralAmounts.filter(([key, _val]) => (0, types_1.currencyIdToMonetaryCurrency)(key.args[0].wrapped).name === this.wrappedCurrency.name);
            // reduce from [[this.wrapped, collateral], amount][] pairs to [collateral, sumAmount][] map
            const perCollateralCurrencyCollateralAmounts = perWrappedCurrencyCollateralAmounts.reduce((amounts, [key, amount]) => {
                const collateralCurrency = (0, types_1.currencyIdToMonetaryCurrency)(key.args[0].collateral);
                let collateralAmount = (0, utils_1.newMonetaryAmount)(amount.toString(), collateralCurrency);
                if (amounts.has(collateralCurrency)) {
                    // .has() is true, hence non-null
                    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                    collateralAmount = collateralAmount.add(amounts.get(collateralCurrency));
                }
                amounts.set(collateralCurrency, collateralAmount);
                return amounts;
            }, new Map());
            // finally convert the CollateralAmount sums to issuable amounts and sum those to get the total
            const [perCollateralCurrencyIssuableAmounts, issuedAmountBtc] = yield Promise.all([
                Promise.all([...perCollateralCurrencyCollateralAmounts.values()].map((collateralAmount) => this.calculateCapacity(collateralAmount))),
                this.getTotalIssuedAmount(),
            ]);
            const totalIssuableAmount = perCollateralCurrencyIssuableAmounts.reduce((acc, v) => acc.add(v));
            return totalIssuableAmount.sub(issuedAmountBtc);
        });
    }
    calculateCapacity(collateral) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                const [exchangeRate, secureCollateralThreshold] = yield Promise.all([
                    this.oracleAPI.getExchangeRate(collateral.currency),
                    this.getSecureCollateralThreshold(collateral.currency),
                ]);
                const unusedCollateral = collateral.div(secureCollateralThreshold);
                return exchangeRate.toBase(unusedCollateral);
            }
            catch (error) {
                return (0, utils_1.newMonetaryAmount)(0, this.wrappedCurrency);
            }
        });
    }
    selectRandomVaultIssue(amount) {
        return __awaiter(this, void 0, void 0, function* () {
            const vaults = yield this.getVaultsWithIssuableTokens();
            for (const [id, issuableAmount] of vaults) {
                if (issuableAmount.gte(amount)) {
                    return id;
                }
            }
            return Promise.reject(new Error("Did not find vault with sufficient collateral"));
        });
    }
    selectRandomVaultRedeem(amount) {
        return __awaiter(this, void 0, void 0, function* () {
            // Selects the first vault with sufficient tokens
            const vaults = yield this.list();
            for (const vault of vaults) {
                if (vault.issuedTokens.gte(amount)) {
                    return vault.id;
                }
            }
            return Promise.reject(new Error("Did not find vault with sufficient locked BTC"));
        });
    }
    getPremiumRedeemVaults() {
        return __awaiter(this, void 0, void 0, function* () {
            const map = new Map();
            const vaults = yield this.getVaultsEligibleForRedeeming();
            const premiumRedeemVaultPredicates = yield Promise.all(vaults
                .map((vault) => this.isBelowPremiumThreshold(vault.id)));
            vaults
                .filter((_, index) => premiumRedeemVaultPredicates[index])
                .forEach((vault) => map.set(vault.id, vault.getRedeemableTokens()));
            return map;
        });
    }
    getVaultsWithIssuableTokens() {
        return __awaiter(this, void 0, void 0, function* () {
            const map = new Map();
            const [vaults, activeBlockNumber] = yield Promise.all([
                this.list(),
                this.systemAPI.getCurrentActiveBlockNumber(),
            ]);
            const issuableTokens = yield Promise.all(vaults
                .filter((vault) => {
                const bannedUntilBlockNumber = vault.bannedUntil || 0;
                return vault.status === types_1.VaultStatusExt.Active && bannedUntilBlockNumber < activeBlockNumber;
            })
                .map((vault) => {
                return new Promise((resolve, _) => vault.getIssuableTokens().then((amount) => resolve([amount, vault.id])));
            }));
            issuableTokens.forEach(([amount, vaultId]) => map.set(vaultId, amount));
            return map;
        });
    }
    isVaultEligibleForRedeem(vault, activeBlockNumber) {
        const bannedUntilBlockNumber = vault.bannedUntil || 0;
        return ((vault.status === types_1.VaultStatusExt.Active || vault.status === types_1.VaultStatusExt.Inactive) &&
            vault.issuedTokens.gt(vault.toBeRedeemedTokens) &&
            bannedUntilBlockNumber < activeBlockNumber);
    }
    getVaultsEligibleForRedeeming() {
        return __awaiter(this, void 0, void 0, function* () {
            const [vaults, activeBlockNumber] = yield Promise.all([
                this.list(),
                this.systemAPI.getCurrentActiveBlockNumber(),
            ]);
            // only non-banned, non-liquidated vaults with liquidity are eligible for redeems
            const redeemVaults = vaults.filter((vault) => {
                return this.isVaultEligibleForRedeem(vault, activeBlockNumber);
            });
            return redeemVaults;
        });
    }
    getVaultsWithRedeemableTokens() {
        return __awaiter(this, void 0, void 0, function* () {
            const map = new Map();
            const vaults = yield this.getVaultsEligibleForRedeeming();
            vaults
                .sort((vault1, vault2) => {
                // Descending order
                const vault1Redeemable = vault1.getRedeemableTokens().toBig();
                const vault2Redeemable = vault2.getRedeemableTokens().toBig();
                return vault2Redeemable.sub(vault1Redeemable).toNumber();
            })
                .forEach((vault) => map.set(vault.id, vault.getRedeemableTokens()));
            return map;
        });
    }
    isVaultFlaggedForTheft(vaultAccountId, collateralCurrencyIdLiteral, btcTxId) {
        return __awaiter(this, void 0, void 0, function* () {
            const collateralCurrencyId = (0, utils_1.newCurrencyId)(this.api, collateralCurrencyIdLiteral);
            const vaultId = (0, utils_1.newVaultId)(this.api, vaultAccountId.toString(), (0, types_1.currencyIdToMonetaryCurrency)(collateralCurrencyId), this.wrappedCurrency);
            const theftReports = yield this.api.query.relay.theftReports(vaultId, { content: btcTxId });
            return theftReports.isEmpty;
        });
    }
    getLiquidationCollateralThreshold(collateralCurrency) {
        return __awaiter(this, void 0, void 0, function* () {
            const vaultCurrencyPair = (0, utils_1.newVaultCurrencyPair)(this.api, collateralCurrency, this.wrappedCurrency);
            const threshold = yield this.api.query.vaultRegistry.liquidationCollateralThreshold(vaultCurrencyPair);
            if (!threshold.isSome) {
                return Promise.reject(`No liquidation threshold for currency ${collateralCurrency.ticker}`);
            }
            return (0, utils_1.decodeFixedPointType)(threshold.value);
        });
    }
    getPremiumRedeemThreshold(collateralCurrency) {
        return __awaiter(this, void 0, void 0, function* () {
            const vaultCurrencyPair = (0, utils_1.newVaultCurrencyPair)(this.api, collateralCurrency, this.wrappedCurrency);
            const threshold = yield this.api.query.vaultRegistry.premiumRedeemThreshold(vaultCurrencyPair);
            if (!threshold.isSome) {
                return Promise.reject(`No premium redeem threshold for currency ${collateralCurrency.ticker}`);
            }
            return (0, utils_1.decodeFixedPointType)(threshold.value);
        });
    }
    getSecureCollateralThreshold(collateralCurrency) {
        return __awaiter(this, void 0, void 0, function* () {
            const vaultCurrencyPair = (0, utils_1.newVaultCurrencyPair)(this.api, collateralCurrency, this.wrappedCurrency);
            const threshold = yield this.api.query.vaultRegistry.secureCollateralThreshold(vaultCurrencyPair);
            return (0, utils_1.decodeFixedPointType)(threshold.value);
        });
    }
    getAPY(vaultAccountId, collateralCurrency) {
        return __awaiter(this, void 0, void 0, function* () {
            const vault = yield this.get(vaultAccountId, collateralCurrency);
            const [feesWrapped, lockedCollateral, blockRewardsAPY] = yield Promise.all([
                yield this.getWrappedReward(vaultAccountId, collateralCurrency),
                (yield this.tokensAPI.balance((0, types_1.currencyIdToMonetaryCurrency)(vault.id.currencies.collateral), vaultAccountId)).reserved,
                this.getBlockRewardAPY(vaultAccountId, vaultAccountId, collateralCurrency, (0, types_1.tickerToCurrencyIdLiteral)(this.governanceCurrency.ticker)),
            ]);
            return (yield this.feeAPI.calculateAPY(feesWrapped, lockedCollateral)).add(blockRewardsAPY);
        });
    }
    getPunishmentFee() {
        return __awaiter(this, void 0, void 0, function* () {
            const fee = yield this.api.query.fee.punishmentFee();
            return (0, utils_1.decodeFixedPointType)(fee);
        });
    }
    wrapCurrency(amount) {
        return this.api.createType("BalanceWrapper", {
            amount: this.api.createType("u128", amount.toString()),
            currencyId: (0, utils_1.newCurrencyId)(this.api, (0, types_1.tickerToCurrencyIdLiteral)(amount.currency.ticker)),
        });
    }
    unwrapCurrency(wrappedBalance) {
        return (0, utils_1.newMonetaryAmount)(wrappedBalance.amount.toString(), (0, types_1.currencyIdToMonetaryCurrency)(wrappedBalance.currencyId));
    }
    parseVaultStatus(status) {
        if (status.isActive) {
            return status.asActive.isTrue ? types_1.VaultStatusExt.Active : types_1.VaultStatusExt.Inactive;
        }
        else if (status.isLiquidated) {
            return types_1.VaultStatusExt.Liquidated;
        }
        else if (status.isCommittedTheft) {
            return types_1.VaultStatusExt.CommittedTheft;
        }
        else {
            throw new Error("Unknown vault status");
        }
    }
    parseVault(vault, network) {
        return __awaiter(this, void 0, void 0, function* () {
            const collateralCurrency = (0, types_1.currencyIdToMonetaryCurrency)(vault.id.currencies.collateral);
            const replaceCollateral = (0, utils_1.newMonetaryAmount)(vault.replaceCollateral.toString(), collateralCurrency);
            const liquidatedCollateral = (0, utils_1.newMonetaryAmount)(vault.liquidatedCollateral.toString(), collateralCurrency);
            const backingCollateral = yield this.computeBackingCollateral(vault.id);
            return new types_1.VaultExt(this.api, this.oracleAPI, this.systemAPI, (0, utils_1.parseWallet)(vault.wallet, network), backingCollateral, vault.id, this.parseVaultStatus(vault.status), vault.bannedUntil.isSome ? vault.bannedUntil.value.toNumber() : undefined, (0, utils_1.newMonetaryAmount)(vault.toBeIssuedTokens.toString(), this.wrappedCurrency), (0, utils_1.newMonetaryAmount)(vault.issuedTokens.toString(), this.wrappedCurrency), (0, utils_1.newMonetaryAmount)(vault.toBeRedeemedTokens.toString(), this.wrappedCurrency), (0, utils_1.newMonetaryAmount)(vault.toBeReplacedTokens.toString(), this.wrappedCurrency), replaceCollateral, liquidatedCollateral);
        });
    }
    reportVaultTheft(vaultAccountId, btcTxId) {
        return __awaiter(this, void 0, void 0, function* () {
            const txInclusionDetails = yield (0, utils_1.getTxProof)(this.electrsAPI, btcTxId);
            const tx = this.api.tx.relay.reportVaultTheft(vaultAccountId, txInclusionDetails.merkleProof, txInclusionDetails.rawTx);
            yield this.transactionAPI.sendLogged(tx, this.api.events.relay.VaultTheft, true);
        });
    }
    toggleIssueRequests(vaultId, acceptNewIssues) {
        return __awaiter(this, void 0, void 0, function* () {
            const currencyPair = vaultId.currencies;
            const tx = this.api.tx.vaultRegistry.acceptNewIssues(currencyPair, acceptNewIssues);
            yield this.transactionAPI.sendLogged(tx, this.api.events.system.ExtrinsicSuccess, true);
        });
    }
}
exports.DefaultVaultsAPI = DefaultVaultsAPI;
//# sourceMappingURL=vaults.js.map