"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());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.decodePermill = exports.getSS58Prefix = exports.queryNominationsMap = exports.encodeVaultId = exports.unwrapRawExchangeRate = exports.convertMoment = exports.parseRedeemRequest = exports.parseRedeemRequestStatus = exports.parseIssueRequest = exports.parseReplaceRequest = exports.addressOrPairAsAccountId = exports.newBalanceWrapper = exports.newForeignAssetId = exports.newCurrencyId = exports.newVaultCurrencyPair = exports.decodeRpcVaultId = exports.newVaultId = exports.newAccountId = exports.parseSystemVault = exports.storageKeyToNthInner = exports.encodeUnsignedFixedPoint = exports.decodeBytesAsString = exports.decodeFixedPointType = exports.uint8ArrayToString = exports.reverseEndiannessHex = exports.ensureHashEncoded = exports.addHexPrefix = exports.stripHexPrefix = exports.reverseEndianness = void 0;
const big_js_1 = __importDefault(require("big.js"));
const util_1 = require("@polkadot/api/util");
const _1 = require(".");
const requestTypes_1 = require("../types/requestTypes");
const utils_1 = require("../utils");
/**
 * Converts endianness of a Uint8Array
 * @param bytes Uint8Array, to be converted LE<>BE
 */
function reverseEndianness(bytes) {
    let offset = bytes.length;
    for (let index = 0; index < bytes.length; index += bytes.length) {
        offset--;
        for (let x = 0; x < offset; x++) {
            const b = bytes[index + x];
            bytes[index + x] = bytes[index + offset];
            bytes[index + offset] = b;
            offset--;
        }
    }
    return bytes;
}
exports.reverseEndianness = reverseEndianness;
function isHexPrefixed(str) {
    return str.slice(0, 2) === "0x";
}
/**
 * Remove the `0x` hex prefix if present
 * @param str
 */
function stripHexPrefix(str) {
    return isHexPrefixed(str) ? str.slice(2) : str;
}
exports.stripHexPrefix = stripHexPrefix;
/**
 * Ensure the `0x` hex prefix is present
 * @param str
 **/
function addHexPrefix(str) {
    return isHexPrefixed(str) ? str : "0x" + str;
}
exports.addHexPrefix = addHexPrefix;
/**
 * Ensure a hash value is an encoded H256
 * @param api The polkadot API promise used to encode if necessary
 * @param hash The either H256 or string encoded hash
 **/
function ensureHashEncoded(api, hash) {
    if (typeof hash === "string") {
        return api.createType("H256", addHexPrefix(hash));
    }
    else {
        return hash;
    }
}
exports.ensureHashEncoded = ensureHashEncoded;
/**
 * Reverse the endianness of the given hex string
 * @dev Will remove `0x` prefix if present
 * @param hex
 */
function reverseEndiannessHex(hex) {
    const arr = stripHexPrefix(hex).match(/.{1,2}/g) || [];
    const bytes = new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
    return reverseEndianness(bytes).reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
}
exports.reverseEndiannessHex = reverseEndiannessHex;
/**
 * Converts a Uint8Array to string
 * @dev Will remove `0x` prefix if present
 * @param bytes
 */
function uint8ArrayToString(bytes) {
    return stripHexPrefix(bytes.toString()).split("").join("");
}
exports.uint8ArrayToString = uint8ArrayToString;
function decodeFixedPointType(x) {
    const xBig = new big_js_1.default(x.toString());
    const scalingFactor = new big_js_1.default(Math.pow(10, _1.FIXEDI128_SCALING_FACTOR));
    return xBig.div(scalingFactor);
}
exports.decodeFixedPointType = decodeFixedPointType;
/**
 * Convert Bytes to a string. Will remove `0x` prefix if present.
 * @param bytes Bytes to decode
 * @returns the decoded string
 */
function decodeBytesAsString(bytes) {
    return Buffer.from(stripHexPrefix(bytes.toString()), "hex").toString();
}
exports.decodeBytesAsString = decodeBytesAsString;
function encodeUnsignedFixedPoint(api, x) {
    const scalingFactor = new big_js_1.default(Math.pow(10, _1.FIXEDI128_SCALING_FACTOR));
    // If there are any decimals left after scaling up by the scaling factor,
    // the resulting FixedU128 will be wrong. As such, trim any decimals.
    const xScaled = x.mul(scalingFactor).round(0, 0);
    return api.createType("FixedU128", xScaled.toFixed());
}
exports.encodeUnsignedFixedPoint = encodeUnsignedFixedPoint;
function storageKeyToNthInner(s, n = 0) {
    return s.args[n];
}
exports.storageKeyToNthInner = storageKeyToNthInner;
function parseSystemVault(assetRegistryApi, loansAPI, vault, wrappedCurrency, collateralCurrency) {
    return __awaiter(this, void 0, void 0, function* () {
        return {
            toBeIssuedTokens: utils_1.newMonetaryAmount(vault.toBeIssuedTokens.toString(), wrappedCurrency),
            issuedTokens: utils_1.newMonetaryAmount(vault.issuedTokens.toString(), wrappedCurrency),
            toBeRedeemedTokens: utils_1.newMonetaryAmount(vault.toBeRedeemedTokens.toString(), wrappedCurrency),
            collateral: utils_1.newMonetaryAmount(vault.collateral.toString(), collateralCurrency),
            currencyPair: {
                collateralCurrency: yield _1.currencyIdToMonetaryCurrency(assetRegistryApi, loansAPI, vault.currencyPair.collateral),
                wrappedCurrency: yield _1.currencyIdToMonetaryCurrency(assetRegistryApi, loansAPI, vault.currencyPair.wrapped),
            },
        };
    });
}
exports.parseSystemVault = parseSystemVault;
function newAccountId(api, accountId) {
    return api.createType("AccountId", accountId);
}
exports.newAccountId = newAccountId;
function newVaultId(api, accountId, collateralCurrency, wrappedCurrency) {
    const parsedAccountId = newAccountId(api, accountId);
    const vaultCurrencyPair = newVaultCurrencyPair(api, collateralCurrency, wrappedCurrency);
    return api.createType("InterbtcPrimitivesVaultId", { account_id: parsedAccountId, currencies: vaultCurrencyPair });
}
exports.newVaultId = newVaultId;
function decodeRpcVaultId(api, assetRegistry, loansAPI, vaultId) {
    return __awaiter(this, void 0, void 0, function* () {
        const [collateralCcy, wrappedCcy] = yield Promise.all([
            _1.currencyIdToMonetaryCurrency(assetRegistry, loansAPI, vaultId.currencies.collateral),
            _1.currencyIdToMonetaryCurrency(assetRegistry, loansAPI, vaultId.currencies.wrapped),
        ]);
        return newVaultId(api, vaultId.account_id.toString(), collateralCcy, wrappedCcy);
    });
}
exports.decodeRpcVaultId = decodeRpcVaultId;
function newVaultCurrencyPair(api, collateralCurrency, wrappedCurrency) {
    const collateralCurrencyId = newCurrencyId(api, collateralCurrency);
    const wrappedCurrencyId = newCurrencyId(api, wrappedCurrency);
    return api.createType("InterbtcPrimitivesVaultCurrencyPair", {
        collateral: collateralCurrencyId,
        wrapped: wrappedCurrencyId,
    });
}
exports.newVaultCurrencyPair = newVaultCurrencyPair;
function newCurrencyId(api, currency) {
    const identifier = _1.getCurrencyIdentifier(currency);
    return api.createType("InterbtcPrimitivesCurrencyId", identifier);
}
exports.newCurrencyId = newCurrencyId;
function newForeignAssetId(api, id) {
    return api.createType("u32", id);
}
exports.newForeignAssetId = newForeignAssetId;
function newBalanceWrapper(api, atomicAmount) {
    return api.createType("BalanceWrapper", {
        amount: api.createType("Text", big_js_1.default(atomicAmount).toString()),
    });
}
exports.newBalanceWrapper = newBalanceWrapper;
function addressOrPairAsAccountId(api, addyOrpair) {
    const addressString = util_1.isKeyringPair(addyOrpair) ? addyOrpair.address : addyOrpair.toString();
    return newAccountId(api, addressString);
}
exports.addressOrPairAsAccountId = addressOrPairAsAccountId;
function parseReplaceRequest(assetRegistry, loansAPI, req, network, wrappedCurrency, id) {
    return __awaiter(this, void 0, void 0, function* () {
        const collateralCurrency = yield _1.currencyIdToMonetaryCurrency(assetRegistry, loansAPI, req.oldVault.currencies.collateral);
        return {
            id: stripHexPrefix(id.toString()),
            btcAddress: _1.encodeBtcAddress(req.btcAddress, network),
            newVault: req.newVault,
            oldVault: req.oldVault,
            amount: utils_1.newMonetaryAmount(req.amount.toString(), wrappedCurrency),
            griefingCollateral: utils_1.newMonetaryAmount(req.griefingCollateral.toString(), collateralCurrency),
            collateral: utils_1.newMonetaryAmount(req.collateral.toString(), collateralCurrency),
            acceptTime: req.acceptTime.toNumber(),
            period: req.period.toNumber(),
            btcHeight: req.btcHeight.toNumber(),
            status: req.status,
        };
    });
}
exports.parseReplaceRequest = parseReplaceRequest;
function parseIssueRequest(vaultsAPI, assetRegistry, loansAPI, req, network, id) {
    return __awaiter(this, void 0, void 0, function* () {
        const status = req.status.isCompleted
            ? requestTypes_1.IssueStatus.Completed
            : req.status.isCancelled
                ? requestTypes_1.IssueStatus.Cancelled
                : requestTypes_1.IssueStatus.PendingWithBtcTxNotFound;
        const collateralCurrency = yield _1.currencyIdToMonetaryCurrency(assetRegistry, loansAPI, req.vault.currencies.collateral);
        return {
            id: stripHexPrefix(id.toString()),
            creationBlock: req.opentime.toNumber(),
            vaultWrappedAddress: _1.encodeBtcAddress(req.btcAddress, network),
            vaultId: req.vault,
            userParachainAddress: req.requester.toString(),
            vaultWalletPubkey: req.btcPublicKey.toString(),
            bridgeFee: utils_1.newMonetaryAmount(req.fee.toString(), vaultsAPI.getWrappedCurrency()),
            wrappedAmount: utils_1.newMonetaryAmount(req.amount.toString(), vaultsAPI.getWrappedCurrency()),
            griefingCollateral: utils_1.newMonetaryAmount(req.griefingCollateral.toString(), collateralCurrency),
            status,
            period: req.period.toNumber(),
        };
    });
}
exports.parseIssueRequest = parseIssueRequest;
function parseRedeemRequestStatus(req, redeemPeriod, activeBlockCount) {
    const primStatus = req.status;
    // check obvious final states first
    if (primStatus.isCompleted) {
        return requestTypes_1.RedeemStatus.Completed;
    }
    if (primStatus.isReimbursed) {
        return requestTypes_1.RedeemStatus.Reimbursed;
    }
    if (primStatus.isRetried) {
        return requestTypes_1.RedeemStatus.Retried;
    }
    // now check if pending is actually expired
    const maxPeriod = Math.max(req.period.toNumber(), redeemPeriod);
    const openTime = req.opentime.toNumber();
    if (openTime + maxPeriod < activeBlockCount) {
        return requestTypes_1.RedeemStatus.Expired;
    }
    return requestTypes_1.RedeemStatus.PendingWithBtcTxNotFound;
}
exports.parseRedeemRequestStatus = parseRedeemRequestStatus;
function parseRedeemRequest(vaultsAPI, assetRegistry, loansAPI, req, network, id, redeemPeriod, activeBlockCount) {
    return __awaiter(this, void 0, void 0, function* () {
        const status = parseRedeemRequestStatus(req, redeemPeriod, activeBlockCount);
        const collateralCurrency = yield _1.currencyIdToMonetaryCurrency(assetRegistry, loansAPI, req.vault.currencies.collateral);
        return {
            id: stripHexPrefix(id.toString()),
            userParachainAddress: req.redeemer.toString(),
            amountBTC: utils_1.newMonetaryAmount(req.amountBtc.toString(), vaultsAPI.getWrappedCurrency()),
            collateralPremium: utils_1.newMonetaryAmount(req.premium.toString(), collateralCurrency),
            bridgeFee: utils_1.newMonetaryAmount(req.fee.toString(), vaultsAPI.getWrappedCurrency()),
            btcTransferFee: utils_1.newMonetaryAmount(req.transferFeeBtc.toString(), vaultsAPI.getWrappedCurrency()),
            creationBlock: req.opentime.toNumber(),
            vaultId: req.vault,
            userBTCAddress: _1.encodeBtcAddress(req.btcAddress, network),
            status,
            period: req.period.toNumber(),
        };
    });
}
exports.parseRedeemRequest = parseRedeemRequest;
function convertMoment(moment) {
    return new Date(moment.toNumber());
}
exports.convertMoment = convertMoment;
function unwrapRawExchangeRate(option) {
    return option.isSome ? option.value : undefined;
}
exports.unwrapRawExchangeRate = unwrapRawExchangeRate;
function encodeVaultId(assetRegistry, loansAPI, id) {
    return __awaiter(this, void 0, void 0, function* () {
        const [wrappedCurrency, collateralCurrency] = yield Promise.all([
            _1.currencyIdToMonetaryCurrency(assetRegistry, loansAPI, id.currencies.wrapped),
            _1.currencyIdToMonetaryCurrency(assetRegistry, loansAPI, id.currencies.collateral),
        ]);
        const wrappedId = _1.isForeignAsset(wrappedCurrency)
            ? wrappedCurrency.foreignAsset.id.toString()
            : _1.isLendToken(wrappedCurrency)
                ? wrappedCurrency.lendToken.id
                : wrappedCurrency.ticker;
        const collateralId = _1.isForeignAsset(collateralCurrency)
            ? collateralCurrency.foreignAsset.id.toString()
            : _1.isLendToken(collateralCurrency)
                ? collateralCurrency.lendToken.id.toString()
                : collateralCurrency.ticker;
        return `${id.accountId.toString()}-${wrappedId}-${collateralId}`;
    });
}
exports.encodeVaultId = encodeVaultId;
function queryNominationsMap(assetRegistry, loansAPI, map, vaultId) {
    return __awaiter(this, void 0, void 0, function* () {
        for (const [entryVaultId, entryNonce] of map.entries()) {
            if ((yield encodeVaultId(assetRegistry, loansAPI, entryVaultId)) ===
                (yield encodeVaultId(assetRegistry, loansAPI, vaultId))) {
                return entryNonce;
            }
        }
        return undefined;
    });
}
exports.queryNominationsMap = queryNominationsMap;
function getSS58Prefix(api) {
    var _a;
    return Number((_a = api.registry.chainSS58) === null || _a === void 0 ? void 0 : _a.toString());
}
exports.getSS58Prefix = getSS58Prefix;
function decodePermill(amount, inPercentage = false) {
    const decodedInDecimals = big_js_1.default(amount.toString()).div(_1.PERMILL_BASE);
    if (inPercentage) {
        return decodedInDecimals.mul(100);
    }
    return decodedInDecimals;
}
exports.decodePermill = decodePermill;
//# sourceMappingURL=encoding.js.map