"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 bignumber_js_1 = __importDefault(require("bignumber.js"));
const types_1 = require("../../../polkadot/types");
const sinon_1 = __importDefault(require("sinon"));
const launchOffering_1 = require("../launchOffering");
const mocks_1 = require("../../../testUtils/mocks");
const types_2 = require("../../../types");
const utilsConversionModule = __importStar(require("../../../utils/conversion"));
const utilsInternalModule = __importStar(require("../../../utils/internal"));
jest.mock('~/api/entities/Asset', require("../../../testUtils/mocks/entities").mockAssetModule('~/api/entities/Asset'));
jest.mock('~/api/entities/Identity', require("../../../testUtils/mocks/entities").mockIdentityModule('~/api/entities/Identity'));
jest.mock('~/api/entities/Offering', require("../../../testUtils/mocks/entities").mockOfferingModule('~/api/entities/Offering'));
jest.mock('~/api/entities/DefaultPortfolio', require("../../../testUtils/mocks/entities").mockDefaultPortfolioModule('~/api/entities/DefaultPortfolio'));
describe('launchOffering procedure', () => {
    let mockContext;
    let stringToTickerStub;
    let portfolioIdToMeshPortfolioIdStub;
    let portfolioLikeToPortfolioIdStub;
    let bigNumberToU64Stub;
    let dateToMomentStub;
    let bigNumberToBalanceStub;
    let stoTierToPriceTierStub;
    let stringToTextStub;
    let portfolioIdToPortfolioStub;
    let ticker;
    let offeringPortfolio;
    let portfolio;
    let offeringPortfolioId;
    let raisingPortfolio;
    let raisingPortfolioId;
    let raisingCurrency;
    let venueId;
    let venue;
    let name;
    let start;
    let end;
    let amount;
    let price;
    let minInvestment;
    let rawTicker;
    let rawOfferingPortfolio;
    let rawRaisingPortfolio;
    let rawRaisingCurrency;
    let rawVenueId;
    let rawName;
    let rawStart;
    let rawEnd;
    let rawTiers;
    let rawMinInvestment;
    let offering;
    let args;
    beforeAll(() => {
        mocks_1.dsMockUtils.initMocks();
        mocks_1.procedureMockUtils.initMocks();
        mocks_1.entityMockUtils.initMocks();
        stringToTickerStub = sinon_1.default.stub(utilsConversionModule, 'stringToTicker');
        portfolioIdToMeshPortfolioIdStub = sinon_1.default.stub(utilsConversionModule, 'portfolioIdToMeshPortfolioId');
        portfolioLikeToPortfolioIdStub = sinon_1.default.stub(utilsConversionModule, 'portfolioLikeToPortfolioId');
        stoTierToPriceTierStub = sinon_1.default.stub(utilsConversionModule, 'stoTierToPriceTier');
        bigNumberToU64Stub = sinon_1.default.stub(utilsConversionModule, 'bigNumberToU64');
        dateToMomentStub = sinon_1.default.stub(utilsConversionModule, 'dateToMoment');
        bigNumberToBalanceStub = sinon_1.default.stub(utilsConversionModule, 'bigNumberToBalance');
        stringToTextStub = sinon_1.default.stub(utilsConversionModule, 'stringToText');
        portfolioIdToPortfolioStub = sinon_1.default.stub(utilsConversionModule, 'portfolioIdToPortfolio');
        ticker = 'tickerFrozen';
        rawTicker = mocks_1.dsMockUtils.createMockTicker(ticker);
        offeringPortfolio = 'oneDid';
        raisingPortfolio = 'treasuryDid';
        offeringPortfolioId = { did: offeringPortfolio };
        raisingPortfolioId = { did: raisingPortfolio };
        raisingCurrency = 'USD';
        venueId = new bignumber_js_1.default(1);
        name = 'someOffering';
        const now = new Date();
        start = new Date(now.getTime() + 10000);
        end = new Date(start.getTime() + 10000);
        amount = new bignumber_js_1.default(100);
        price = new bignumber_js_1.default(1000);
        minInvestment = new bignumber_js_1.default(50);
        rawOfferingPortfolio = mocks_1.dsMockUtils.createMockPortfolioId({
            did: mocks_1.dsMockUtils.createMockIdentityId(offeringPortfolio),
            kind: mocks_1.dsMockUtils.createMockPortfolioKind('Default'),
        });
        rawRaisingPortfolio = mocks_1.dsMockUtils.createMockPortfolioId({
            did: mocks_1.dsMockUtils.createMockIdentityId(raisingPortfolio),
            kind: mocks_1.dsMockUtils.createMockPortfolioKind('Default'),
        });
        rawRaisingCurrency = mocks_1.dsMockUtils.createMockTicker(raisingCurrency);
        rawVenueId = mocks_1.dsMockUtils.createMockU64(venueId);
        rawName = mocks_1.dsMockUtils.createMockText(name);
        rawStart = mocks_1.dsMockUtils.createMockMoment(new bignumber_js_1.default(start.getTime()));
        rawEnd = mocks_1.dsMockUtils.createMockMoment(new bignumber_js_1.default(end.getTime()));
        rawTiers = [
            mocks_1.dsMockUtils.createMockPriceTier({
                total: mocks_1.dsMockUtils.createMockBalance(amount),
                price: mocks_1.dsMockUtils.createMockBalance(price),
            }),
        ];
        rawMinInvestment = mocks_1.dsMockUtils.createMockBalance(minInvestment);
        offering = 'offering';
    });
    let addTransactionStub;
    beforeEach(() => {
        venue = mocks_1.entityMockUtils.getVenueInstance({
            id: venueId,
            details: {
                type: types_2.VenueType.Sto,
            },
        });
        addTransactionStub = mocks_1.procedureMockUtils.getAddTransactionStub().returns([offering]);
        mockContext = mocks_1.dsMockUtils.getContextInstance();
        stringToTickerStub.withArgs(ticker, mockContext).returns(rawTicker);
        stringToTickerStub.withArgs(raisingCurrency, mockContext).returns(rawRaisingCurrency);
        portfolioLikeToPortfolioIdStub.withArgs(offeringPortfolio).returns(offeringPortfolioId);
        portfolioIdToMeshPortfolioIdStub
            .withArgs(offeringPortfolioId, mockContext)
            .returns(rawOfferingPortfolio);
        portfolioLikeToPortfolioIdStub.withArgs(raisingPortfolio).returns(raisingPortfolioId);
        portfolioIdToMeshPortfolioIdStub
            .withArgs(raisingPortfolioId, mockContext)
            .returns(rawRaisingPortfolio);
        stoTierToPriceTierStub.withArgs({ amount, price }, mockContext).returns(rawTiers[0]);
        bigNumberToU64Stub.withArgs(venue.id, mockContext).returns(rawVenueId);
        dateToMomentStub.withArgs(start, mockContext).returns(rawStart);
        dateToMomentStub.withArgs(end, mockContext).returns(rawEnd);
        stringToTextStub.withArgs(name, mockContext).returns(rawName);
        bigNumberToBalanceStub.withArgs(minInvestment, mockContext).returns(rawMinInvestment);
        portfolio = mocks_1.entityMockUtils.getDefaultPortfolioInstance(offeringPortfolioId);
        portfolioIdToPortfolioStub.withArgs(offeringPortfolioId, mockContext).returns(portfolio);
        args = {
            ticker,
            offeringPortfolio,
            raisingPortfolio,
            raisingCurrency,
            venue,
            name,
            start,
            end,
            tiers: [{ amount, price }],
            minInvestment,
        };
    });
    afterEach(() => {
        mocks_1.entityMockUtils.reset();
        mocks_1.procedureMockUtils.reset();
        mocks_1.dsMockUtils.reset();
    });
    afterAll(() => {
        mocks_1.procedureMockUtils.cleanup();
        mocks_1.dsMockUtils.cleanup();
    });
    test('should throw an error if no valid Venue was supplied or found', () => __awaiter(void 0, void 0, void 0, function* () {
        portfolio.getAssetBalances.resolves([{ free: new bignumber_js_1.default(20) }]);
        mocks_1.entityMockUtils.configureMocks({
            identityOptions: {
                getVenues: [mocks_1.entityMockUtils.getVenueInstance({ details: { type: types_2.VenueType.Exchange } })],
            },
        });
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
            offeringPortfolioId,
            raisingPortfolioId,
        });
        let err;
        try {
            yield launchOffering_1.prepareLaunchOffering.call(proc, Object.assign(Object.assign({}, args), { venue: mocks_1.entityMockUtils.getVenueInstance({ exists: false }) }));
        }
        catch (error) {
            err = error;
        }
        expect(err === null || err === void 0 ? void 0 : err.message).toBe('A valid Venue for the Offering was neither supplied nor found');
        err = undefined;
        try {
            yield launchOffering_1.prepareLaunchOffering.call(proc, Object.assign(Object.assign({}, args), { venue: undefined }));
        }
        catch (error) {
            err = error;
        }
        expect(err === null || err === void 0 ? void 0 : err.message).toBe('A valid Venue for the Offering was neither supplied nor found');
    }));
    test("should throw an error if Asset tokens offered exceed the Portfolio's balance", () => __awaiter(void 0, void 0, void 0, function* () {
        portfolio.getAssetBalances.resolves([{ free: new bignumber_js_1.default(1) }]);
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
            offeringPortfolioId,
            raisingPortfolioId,
        });
        let err;
        try {
            yield launchOffering_1.prepareLaunchOffering.call(proc, args);
        }
        catch (error) {
            err = error;
        }
        expect(err === null || err === void 0 ? void 0 : err.message).toBe("There isn't enough free balance in the offering Portfolio");
    }));
    test('should add a create fundraiser transaction to the queue', () => __awaiter(void 0, void 0, void 0, function* () {
        portfolio.getAssetBalances.resolves([{ free: new bignumber_js_1.default(1000) }]);
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
            offeringPortfolioId,
            raisingPortfolioId,
        });
        const transaction = mocks_1.dsMockUtils.createTxStub('sto', 'createFundraiser');
        let result = yield launchOffering_1.prepareLaunchOffering.call(proc, args);
        sinon_1.default.assert.calledWith(addTransactionStub, sinon_1.default.match({
            transaction,
            resolvers: sinon_1.default.match.array,
            args: [
                rawOfferingPortfolio,
                rawTicker,
                rawRaisingPortfolio,
                rawRaisingCurrency,
                rawTiers,
                rawVenueId,
                rawStart,
                rawEnd,
                rawMinInvestment,
                rawName,
            ],
        }));
        expect(result).toBe(offering);
        mocks_1.entityMockUtils.configureMocks({
            venueOptions: {
                details: {
                    type: types_2.VenueType.Sto,
                },
            },
            identityOptions: {
                getVenues: [venue],
            },
            defaultPortfolioOptions: {
                getAssetBalances: [{ free: new bignumber_js_1.default(1000) }],
            },
        });
        result = yield launchOffering_1.prepareLaunchOffering.call(proc, Object.assign(Object.assign({}, args), { venue: undefined, start: undefined, end: undefined }));
        sinon_1.default.assert.calledWith(addTransactionStub, sinon_1.default.match({
            transaction,
            resolvers: sinon_1.default.match.array,
            args: [
                rawOfferingPortfolio,
                rawTicker,
                rawRaisingPortfolio,
                rawRaisingCurrency,
                rawTiers,
                rawVenueId,
                null,
                null,
                rawMinInvestment,
                rawName,
            ],
        }));
        expect(result).toEqual(offering);
    }));
    describe('stoResolver', () => {
        const filterEventRecordsStub = sinon_1.default.stub(utilsInternalModule, 'filterEventRecords');
        const stoId = new bignumber_js_1.default(15);
        beforeAll(() => {
            mocks_1.entityMockUtils.initMocks({ offeringOptions: { ticker, id: stoId } });
        });
        beforeEach(() => {
            filterEventRecordsStub.returns([
                mocks_1.dsMockUtils.createMockIEvent(['filler', mocks_1.dsMockUtils.createMockU64(stoId)]),
            ]);
        });
        afterEach(() => {
            filterEventRecordsStub.reset();
        });
        test('should return the new Offering', () => {
            const result = launchOffering_1.createOfferingResolver(ticker, mockContext)({});
            expect(result).toEqual(expect.objectContaining({ asset: expect.objectContaining({ ticker }), id: stoId }));
        });
    });
    describe('getAuthorization', () => {
        test('should return the appropriate roles and permissions', () => {
            const proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
                offeringPortfolioId,
                raisingPortfolioId,
            });
            const boundFunc = launchOffering_1.getAuthorization.bind(proc);
            const portfolios = [
                'offering',
                'raising',
            ];
            portfolioIdToPortfolioStub.withArgs(offeringPortfolioId, mockContext).returns(portfolios[0]);
            portfolioIdToPortfolioStub.withArgs(raisingPortfolioId, mockContext).returns(portfolios[1]);
            const roles = [
                { type: types_2.RoleType.PortfolioCustodian, portfolioId: offeringPortfolioId },
                { type: types_2.RoleType.PortfolioCustodian, portfolioId: raisingPortfolioId },
            ];
            expect(boundFunc(args)).toEqual({
                roles,
                permissions: {
                    transactions: [types_1.TxTags.sto.CreateFundraiser],
                    assets: [expect.objectContaining({ ticker })],
                    portfolios,
                },
            });
        });
    });
    describe('prepareStorage', () => {
        test('should return the offering and raising portfolio ids', () => __awaiter(void 0, void 0, void 0, function* () {
            const proc = mocks_1.procedureMockUtils.getInstance(mockContext);
            const boundFunc = launchOffering_1.prepareStorage.bind(proc);
            const result = yield boundFunc(args);
            expect(result).toEqual({
                offeringPortfolioId,
                raisingPortfolioId,
            });
        }));
    });
});
//# sourceMappingURL=launchOffering.js.map