"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
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 });
const chai_1 = require("../../chai");
const sinon_1 = __importDefault(require("sinon"));
const api_1 = require("@polkadot/api");
const src_1 = require("../../../src/");
const allThingsEncoding = __importStar(require("../../../src/utils/encoding"));
describe("DefaultAssetRegistryAPI", () => {
    let api;
    let assetRegistryApi;
    let mockMetadata;
    let mockStorageKey;
    const mockStorageKeyValue = 42;
    const mockMetadataValues = {
        name: "Mock Coin One",
        symbol: "MCO",
        decimals: 8,
        existentialDeposit: 42,
        feesPerMinute: 15,
        coingeckoId: "mock-coin-one",
    };
    before(() => {
        api = new api_1.ApiPromise();
        // disconnect immediately to avoid printing errors
        // we only need the instance to create variables
        api.disconnect();
        // register just enough from OrmlTraitsAssetRegistryAssetMetadata to construct
        // meaningful representations for our tests
        api.registerTypes({
            OrmlTraitsAssetRegistryAssetMetadata: {
                name: "Bytes",
                symbol: "Bytes",
                decimals: "u32",
                existentialDeposit: "u128",
                additional: "InterbtcPrimitivesCustomMetadata",
            },
            InterbtcPrimitivesCustomMetadata: {
                feePerSecond: "u128",
                coingeckoId: "Bytes",
            },
        });
    });
    beforeEach(() => {
        assetRegistryApi = new src_1.DefaultAssetRegistryAPI(api);
        // reset to base values
        mockMetadata = {
            name: api.createType("Bytes", mockMetadataValues.name),
            symbol: api.createType("Bytes", mockMetadataValues.symbol),
            decimals: api.createType("u32", mockMetadataValues.decimals),
            existentialDeposit: api.createType("u128", mockMetadataValues.existentialDeposit),
            additional: api.createType("InterbtcPrimitivesCustomMetadata", {
                feePerSecond: api.createType("u128", mockMetadataValues.feesPerMinute),
                coingeckoId: api.createType("Bytes", mockMetadataValues.coingeckoId),
            }),
        };
        // mock return type of storageKeyToNthInner method which only works correctly in integration tests
        const mockedReturn = api.createType("AssetId", mockStorageKeyValue);
        sinon_1.default.stub(allThingsEncoding, "storageKeyToNthInner").returns(mockedReturn);
    });
    afterEach(() => {
        sinon_1.default.restore();
        sinon_1.default.reset();
    });
    describe("getForeignAssets", () => {
        it("should return empty list if chain returns no foreign assets", () => __awaiter(void 0, void 0, void 0, function* () {
            // mock empty list returned from chain
            sinon_1.default.stub(assetRegistryApi, "getAssetRegistryEntries").returns(Promise.resolve([]));
            const actual = yield assetRegistryApi.getForeignAssets();
            chai_1.expect(actual).to.be.empty;
        }));
        it("should ignore empty optionals in foreign assets data from chain", () => __awaiter(void 0, void 0, void 0, function* () {
            const chainDataReturned = [
                // one "good" returned value
                [mockStorageKey, api.createType("Option<OrmlTraitsAssetRegistryAssetMetadata>", mockMetadata)],
                // one empty option
                [mockStorageKey, api.createType("Option<OrmlTraitsAssetRegistryAssetMetadata>", undefined)],
            ];
            sinon_1.default.stub(assetRegistryApi, "getAssetRegistryEntries").returns(Promise.resolve(chainDataReturned));
            const actual = yield assetRegistryApi.getForeignAssets();
            chai_1.expect(actual).to.have.lengthOf(1, `Expected only one currency to be returned, but got ${actual.length}`);
            const actualCurrency = actual[0];
            chai_1.expect(actualCurrency.ticker).to.equal(mockMetadataValues.symbol, `Expected the returned currency ticker to be ${mockMetadataValues.symbol}, but it was ${actualCurrency.ticker}`);
        }));
    });
    describe("unwrapMetadataFromEntries", () => {
        it("should convert foreign asset metadata to currency", () => __awaiter(void 0, void 0, void 0, function* () {
            const actual = src_1.DefaultAssetRegistryAPI.metadataTupleToForeignAsset([mockStorageKey, mockMetadata]);
            chai_1.expect(actual.ticker).to.equal(mockMetadataValues.symbol, `Expected currency ticker to be ${mockMetadataValues.symbol}, but was ${actual.ticker}`);
            chai_1.expect(actual.name).to.equal(mockMetadataValues.name, `Expected currency name to be ${mockMetadataValues.name}, but was ${actual.name}`);
            chai_1.expect(actual.decimals).to.equal(mockMetadataValues.decimals, `Expected currency base to be ${mockMetadataValues.decimals}, but was ${actual.decimals}`);
            chai_1.expect(actual.coingeckoId).to.equal(mockMetadataValues.coingeckoId, `Expected coingecko id to be ${mockMetadataValues.coingeckoId}, but was ${actual.coingeckoId}`);
        }));
    });
    describe("getCollateralForeignAssets", () => {
        // only id matters for these tests
        const mockForeignAssets = [{ id: 1 }, { id: 2 }, { id: 3 }];
        const prepareMocks = (sinon, assetRegistryApi, allForeignAssets, collateralCeilingCurrencyPairs) => {
            sinon.stub(assetRegistryApi, "getForeignAssets").returns(Promise.resolve(allForeignAssets));
            // this return does not matter since individual tests mock extractCollateralCeilingEntryKeys
            // which returns the actual values of interest
            sinon.stub(assetRegistryApi, "getSystemCollateralCeilingEntries").returns(Promise.resolve([]));
            if (collateralCeilingCurrencyPairs !== undefined) {
                sinon
                    .stub(assetRegistryApi, "extractCollateralCeilingEntryKeys")
                    .returns(collateralCeilingCurrencyPairs);
            }
        };
        it("should return empty array if there are no foreign assets", () => __awaiter(void 0, void 0, void 0, function* () {
            prepareMocks(sinon_1.default, assetRegistryApi, []);
            const actual = yield assetRegistryApi.getCollateralForeignAssets();
            chai_1.expect(actual).to.be.empty;
        }));
        it("should return empty array if there are no foreign assets with a collateral ceiling set", () => __awaiter(void 0, void 0, void 0, function* () {
            prepareMocks(sinon_1.default, assetRegistryApi, mockForeignAssets, []);
            const actual = yield assetRegistryApi.getCollateralForeignAssets();
            chai_1.expect(actual).to.be.empty;
        }));
        it("should return only foreign assets, not tokens with collateral ceilings set", () => __awaiter(void 0, void 0, void 0, function* () {
            // pick an asset id that we expect to get returned
            const expectedForeignAssetId = mockForeignAssets[0].id;
            // only bother mocking collateral currencies, the wrapped side is ignored
            const mockCurrencyPairs = [
                {
                    // mocked foreign asset collateral
                    collateral: {
                        isForeignAsset: true,
                        isToken: false,
                        asForeignAsset: api.createType("u32", expectedForeignAssetId),
                        type: "ForeignAsset",
                    },
                },
                {
                    // mocked token collateral (ie. not foreign asset)
                    collateral: {
                        isForeignAsset: false,
                        isToken: true,
                        // logically inconsistent (but trying to trick into having a valid result if this is used when it shouldn't)
                        asForeignAsset: api.createType("u32", mockForeignAssets[mockForeignAssets.length - 1].id),
                        type: "Token",
                    },
                },
            ];
            prepareMocks(sinon_1.default, assetRegistryApi, mockForeignAssets, mockCurrencyPairs);
            const actual = yield assetRegistryApi.getCollateralForeignAssets();
            // expect one returned value
            chai_1.expect(actual).to.have.lengthOf(1);
            const actualAssetId = actual[0].id;
            chai_1.expect(actualAssetId).to.be.eq(expectedForeignAssetId);
        }));
    });
});
//# sourceMappingURL=asset-registry.test.js.map