"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.DefaultAssetRegistryAPI = void 0;
const types_1 = require("@polkadot/types");
const utils_1 = require("../utils");
class DefaultAssetRegistryAPI {
    constructor(api) {
        this.api = api;
    }
    static metadataToCurrency(metadata) {
        const symbol = utils_1.decodeBytesAsString(metadata.symbol);
        const name = utils_1.decodeBytesAsString(metadata.name);
        return {
            name: name,
            ticker: symbol,
            decimals: metadata.decimals.toNumber(),
        };
    }
    // not private for easier testing
    static metadataTupleToForeignAsset([key, metadata]) {
        const keyInner = utils_1.storageKeyToNthInner(key);
        const currencyPart = DefaultAssetRegistryAPI.metadataToCurrency(metadata);
        const coingeckoId = utils_1.decodeBytesAsString(metadata.additional.coingeckoId);
        return Object.assign({ foreignAsset: {
                id: keyInner.toNumber(),
                coingeckoId
            } }, currencyPart);
    }
    // wrapped call for easier mocking in tests
    getAssetRegistryEntries() {
        return __awaiter(this, void 0, void 0, function* () {
            return yield this.api.query.assetRegistry.metadata.entries();
        });
    }
    /**
     * Static method to filter out metadata that can be unwrapped.ie. `Option.isSome !== true`.
     * @param entries The entries from the asset registry.
     * @returns A list of all entries containing metadata.
     */
    static unwrapMetadataFromEntries(entries) {
        return entries
            .filter(([, metadata]) => metadata.isSome)
            .map(([storageKey, metadata]) => [storageKey, metadata.unwrap()]);
    }
    getForeignAssets() {
        return __awaiter(this, void 0, void 0, function* () {
            const entries = yield this.getAssetRegistryEntries();
            return DefaultAssetRegistryAPI.unwrapMetadataFromEntries(entries).map(DefaultAssetRegistryAPI.metadataTupleToForeignAsset);
        });
    }
    getForeignAsset(id) {
        return __awaiter(this, void 0, void 0, function* () {
            const u32Id = id instanceof types_1.u32 ? id : utils_1.newForeignAssetId(this.api, id);
            const optionMetadata = yield this.api.query.assetRegistry.metadata(u32Id);
            if (!optionMetadata.isSome) {
                return Promise.reject(new Error("Foreign asset not found"));
            }
            const currencyPart = DefaultAssetRegistryAPI.metadataToCurrency(optionMetadata.unwrap());
            const coingeckoId = utils_1.decodeBytesAsString(optionMetadata.unwrap().additional.coingeckoId);
            const numberId = id instanceof types_1.u32 ? id.toNumber() : id;
            return Object.assign({ foreignAsset: {
                    id: numberId,
                    coingeckoId
                } }, currencyPart);
        });
    }
    // wrapped call for easier mocking in tests
    getSystemCollateralCeilingEntries() {
        return __awaiter(this, void 0, void 0, function* () {
            return this.api.query.vaultRegistry.systemCollateralCeiling.entries();
        });
    }
    // wrapped call for easier mocking in tests
    extractCollateralCeilingEntryKeys(entries) {
        return entries.map(([key, _]) => utils_1.storageKeyToNthInner(key));
    }
    getCollateralForeignAssets() {
        return __awaiter(this, void 0, void 0, function* () {
            const [collateralCeilingEntries, foreignAssets] = yield Promise.all([
                this.getSystemCollateralCeilingEntries(),
                this.getForeignAssets(),
            ]);
            // get a set of all ids of foreign assets within the collateral ceiling entries
            const collateralForeignAssetIdSet = new Set(this.extractCollateralCeilingEntryKeys(collateralCeilingEntries)
                .map((currencyPair) => currencyPair.collateral)
                .filter((currencyId) => currencyId.isForeignAsset)
                .map((currencyId) => currencyId.asForeignAsset.toNumber()));
            // filter all foreign assets to include only those with a collateral ceiling
            return foreignAssets.filter((foreignAsset) => collateralForeignAssetIdSet.has(foreignAsset.foreignAsset.id));
        });
    }
}
exports.DefaultAssetRegistryAPI = DefaultAssetRegistryAPI;
//# sourceMappingURL=asset-registry.js.map