"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 createSecurityToken_1 = require("../createSecurityToken");
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/TickerReservation', require("../../../testUtils/mocks/entities").mockTickerReservationModule('~/api/entities/TickerReservation'));
jest.mock('~/api/entities/SecurityToken', require("../../../testUtils/mocks/entities").mockSecurityTokenModule('~/api/entities/SecurityToken'));
describe('createSecurityToken procedure', () => {
    let mockContext;
    let stringToTickerStub;
    let numberToBalanceStub;
    let stringToAssetNameStub;
    let booleanToBoolStub;
    let internalTokenTypeToAssetTypeStub;
    let tokenIdentifierToAssetIdentifierStub;
    let stringToFundingRoundNameStub;
    let tokenDocumentToDocumentStub;
    let ticker;
    let name;
    let initialSupply;
    let isDivisible;
    let tokenType;
    let tokenIdentifiers;
    let fundingRound;
    let requireInvestorUniqueness;
    let documents;
    let rawTicker;
    let rawName;
    let rawInitialSupply;
    let rawIsDivisible;
    let rawType;
    let rawIdentifiers;
    let rawFundingRound;
    let rawDisableIu;
    let rawDocuments;
    let args;
    let protocolFees;
    beforeAll(() => {
        mocks_1.dsMockUtils.initMocks({
            contextOptions: {
                balance: {
                    free: new bignumber_js_1.default(1000),
                    locked: new bignumber_js_1.default(0),
                    total: new bignumber_js_1.default(1000),
                },
            },
        });
        mocks_1.procedureMockUtils.initMocks();
        mocks_1.entityMockUtils.initMocks();
        stringToTickerStub = sinon_1.default.stub(utilsConversionModule, 'stringToTicker');
        numberToBalanceStub = sinon_1.default.stub(utilsConversionModule, 'numberToBalance');
        stringToAssetNameStub = sinon_1.default.stub(utilsConversionModule, 'stringToAssetName');
        booleanToBoolStub = sinon_1.default.stub(utilsConversionModule, 'booleanToBool');
        internalTokenTypeToAssetTypeStub = sinon_1.default.stub(utilsConversionModule, 'internalTokenTypeToAssetType');
        tokenIdentifierToAssetIdentifierStub = sinon_1.default.stub(utilsConversionModule, 'tokenIdentifierToAssetIdentifier');
        stringToFundingRoundNameStub = sinon_1.default.stub(utilsConversionModule, 'stringToFundingRoundName');
        tokenDocumentToDocumentStub = sinon_1.default.stub(utilsConversionModule, 'tokenDocumentToDocument');
        ticker = 'someTicker';
        name = 'someName';
        initialSupply = new bignumber_js_1.default(100);
        isDivisible = true;
        tokenType = types_2.KnownTokenType.EquityCommon;
        tokenIdentifiers = [
            {
                type: types_2.TokenIdentifierType.Isin,
                value: '12345',
            },
        ];
        fundingRound = 'Series A';
        requireInvestorUniqueness = true;
        documents = [
            {
                name: 'someDocument',
                uri: 'someUri',
                contentHash: 'someHash',
            },
        ];
        rawTicker = mocks_1.dsMockUtils.createMockTicker(ticker);
        rawName = mocks_1.dsMockUtils.createMockAssetName(name);
        rawInitialSupply = mocks_1.dsMockUtils.createMockBalance(initialSupply.toNumber());
        rawIsDivisible = mocks_1.dsMockUtils.createMockBool(isDivisible);
        rawType = mocks_1.dsMockUtils.createMockAssetType(tokenType);
        rawIdentifiers = tokenIdentifiers.map(({ type, value }) => mocks_1.dsMockUtils.createMockAssetIdentifier({
            [type]: mocks_1.dsMockUtils.createMockU8aFixed(value),
        }));
        rawDocuments = documents.map(({ uri, contentHash, name: docName, type, filedAt }) => mocks_1.dsMockUtils.createMockDocument({
            name: mocks_1.dsMockUtils.createMockDocumentName(docName),
            uri: mocks_1.dsMockUtils.createMockDocumentUri(uri),
            /* eslint-disable @typescript-eslint/naming-convention */
            content_hash: mocks_1.dsMockUtils.createMockDocumentHash({
                H128: mocks_1.dsMockUtils.createMockU8aFixed(contentHash),
            }),
            doc_type: mocks_1.dsMockUtils.createMockOption(type ? mocks_1.dsMockUtils.createMockDocumentType(type) : null),
            filing_date: mocks_1.dsMockUtils.createMockOption(filedAt ? mocks_1.dsMockUtils.createMockMoment(filedAt.getTime()) : null),
            /* eslint-enable @typescript-eslint/naming-convention */
        }));
        rawFundingRound = mocks_1.dsMockUtils.createMockFundingRoundName(fundingRound);
        rawDisableIu = mocks_1.dsMockUtils.createMockBool(!requireInvestorUniqueness);
        args = {
            ticker,
            name,
            isDivisible,
            tokenType,
            tokenIdentifiers,
            fundingRound,
            requireInvestorUniqueness,
            reservationRequired: true,
        };
        protocolFees = [new bignumber_js_1.default(250), new bignumber_js_1.default(150)];
    });
    let addTransactionStub;
    let createAssetTransaction;
    beforeEach(() => {
        addTransactionStub = mocks_1.procedureMockUtils.getAddTransactionStub();
        mocks_1.dsMockUtils.createQueryStub('asset', 'tickerConfig', {
            returnValue: mocks_1.dsMockUtils.createMockTickerRegistrationConfig(),
        });
        mocks_1.dsMockUtils.createQueryStub('asset', 'classicTickers', {
            returnValue: mocks_1.dsMockUtils.createMockOption(),
        });
        createAssetTransaction = mocks_1.dsMockUtils.createTxStub('asset', 'createAsset');
        mockContext = mocks_1.dsMockUtils.getContextInstance();
        stringToTickerStub.withArgs(ticker, mockContext).returns(rawTicker);
        numberToBalanceStub.withArgs(initialSupply, mockContext, isDivisible).returns(rawInitialSupply);
        stringToAssetNameStub.withArgs(name, mockContext).returns(rawName);
        booleanToBoolStub.withArgs(isDivisible, mockContext).returns(rawIsDivisible);
        booleanToBoolStub.withArgs(!requireInvestorUniqueness, mockContext).returns(rawDisableIu);
        internalTokenTypeToAssetTypeStub
            .withArgs(tokenType, mockContext)
            .returns(rawType);
        tokenIdentifierToAssetIdentifierStub
            .withArgs(tokenIdentifiers[0], mockContext)
            .returns(rawIdentifiers[0]);
        stringToFundingRoundNameStub.withArgs(fundingRound, mockContext).returns(rawFundingRound);
        tokenDocumentToDocumentStub
            .withArgs({ uri: documents[0].uri, contentHash: documents[0].contentHash, name: documents[0].name }, mockContext)
            .returns(rawDocuments[0]);
        mockContext.getTransactionFees.withArgs(types_1.TxTags.asset.RegisterTicker).resolves(protocolFees[0]);
        mockContext.getTransactionFees.withArgs(types_1.TxTags.asset.CreateAsset).resolves(protocolFees[1]);
    });
    afterEach(() => {
        mocks_1.entityMockUtils.reset();
        mocks_1.procedureMockUtils.reset();
        mocks_1.dsMockUtils.reset();
    });
    afterAll(() => {
        mocks_1.entityMockUtils.cleanup();
        mocks_1.procedureMockUtils.cleanup();
        mocks_1.dsMockUtils.cleanup();
    });
    test('should throw an error if a token with that ticker has already been launched', () => {
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
            customTypeData: null,
            status: types_2.TickerReservationStatus.TokenCreated,
        });
        return expect(createSecurityToken_1.prepareCreateSecurityToken.call(proc, args)).rejects.toThrow(`A Security Token with ticker "${ticker}" already exists`);
    });
    test("should throw an error if that ticker hasn't been reserved and reservation is required", () => {
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
            customTypeData: null,
            status: types_2.TickerReservationStatus.Free,
        });
        return expect(createSecurityToken_1.prepareCreateSecurityToken.call(proc, args)).rejects.toThrow(`You must first reserve ticker "${ticker}" in order to create a Security Token with it`);
    });
    test('should add a token creation transaction to the queue', () => __awaiter(void 0, void 0, void 0, function* () {
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
            customTypeData: null,
            status: types_2.TickerReservationStatus.Reserved,
        });
        const result = yield createSecurityToken_1.prepareCreateSecurityToken.call(proc, args);
        sinon_1.default.assert.calledWith(addTransactionStub.firstCall, createAssetTransaction, { fee: undefined }, rawName, rawTicker, rawIsDivisible, rawType, rawIdentifiers, rawFundingRound, rawDisableIu);
        expect(result).toMatchObject(mocks_1.entityMockUtils.getSecurityTokenInstance({ ticker }));
        yield createSecurityToken_1.prepareCreateSecurityToken.call(proc, Object.assign(Object.assign({}, args), { initialSupply: new bignumber_js_1.default(0), tokenIdentifiers: undefined, fundingRound: undefined, requireInvestorUniqueness: false }));
        sinon_1.default.assert.calledWith(addTransactionStub.secondCall, createAssetTransaction, { fee: undefined }, rawName, rawTicker, rawIsDivisible, rawType, [], null, rawIsDivisible // disable IU = true
        );
        const issueTransaction = mocks_1.dsMockUtils.createTxStub('asset', 'issue');
        yield createSecurityToken_1.prepareCreateSecurityToken.call(proc, Object.assign(Object.assign({}, args), { initialSupply }));
        sinon_1.default.assert.calledWith(addTransactionStub, issueTransaction, {}, rawTicker, rawInitialSupply);
    }));
    test('should add a token creation transaction to the queue when reservationRequired is false', () => __awaiter(void 0, void 0, void 0, function* () {
        let proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
            customTypeData: null,
            status: types_2.TickerReservationStatus.Reserved,
        });
        let result = yield createSecurityToken_1.prepareCreateSecurityToken.call(proc, Object.assign(Object.assign({}, args), { reservationRequired: false }));
        sinon_1.default.assert.calledWith(addTransactionStub.firstCall, createAssetTransaction, { fee: undefined }, rawName, rawTicker, rawIsDivisible, rawType, rawIdentifiers, rawFundingRound, rawDisableIu);
        expect(result).toMatchObject(mocks_1.entityMockUtils.getSecurityTokenInstance({ ticker }));
        proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
            customTypeData: null,
            status: types_2.TickerReservationStatus.Free,
        });
        result = yield createSecurityToken_1.prepareCreateSecurityToken.call(proc, Object.assign(Object.assign({}, args), { reservationRequired: false }));
        sinon_1.default.assert.calledWith(addTransactionStub.secondCall, createAssetTransaction, { fee: protocolFees[0].plus(protocolFees[1]) }, rawName, rawTicker, rawIsDivisible, rawType, rawIdentifiers, rawFundingRound, rawDisableIu);
        expect(result).toMatchObject(mocks_1.entityMockUtils.getSecurityTokenInstance({ ticker }));
    }));
    test('should waive protocol fees if the token was created in Ethereum', () => __awaiter(void 0, void 0, void 0, function* () {
        mocks_1.dsMockUtils.createQueryStub('asset', 'classicTickers', {
            returnValue: mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockClassicTickerRegistration({
                /* eslint-disable @typescript-eslint/naming-convention */
                eth_owner: 'someAddress',
                is_created: true,
                /* eslint-enable @typescript-eslint/naming-convention */
            })),
        });
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
            customTypeData: null,
            status: types_2.TickerReservationStatus.Reserved,
        });
        const result = yield createSecurityToken_1.prepareCreateSecurityToken.call(proc, args);
        sinon_1.default.assert.calledWith(addTransactionStub.firstCall, createAssetTransaction, { fee: new bignumber_js_1.default(0) }, rawName, rawTicker, rawIsDivisible, rawType, rawIdentifiers, rawFundingRound, rawDisableIu);
        expect(result).toMatchObject(mocks_1.entityMockUtils.getSecurityTokenInstance({ ticker }));
    }));
    test('should add a document add transaction to the queue', () => __awaiter(void 0, void 0, void 0, function* () {
        const rawValue = mocks_1.dsMockUtils.createMockBytes('something');
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
            customTypeData: {
                rawValue,
                id: mocks_1.dsMockUtils.createMockU32(10),
            },
            status: types_2.TickerReservationStatus.Reserved,
        });
        const tx = mocks_1.dsMockUtils.createTxStub('asset', 'addDocuments');
        const result = yield createSecurityToken_1.prepareCreateSecurityToken.call(proc, Object.assign(Object.assign({}, args), { documents }));
        sinon_1.default.assert.calledWith(addTransactionStub, tx, { isCritical: false, batchSize: rawDocuments.length }, rawDocuments, rawTicker);
        expect(result).toMatchObject(mocks_1.entityMockUtils.getSecurityTokenInstance({ ticker }));
    }));
    test('should add a register custom asset type transaction to the queue and use the id for asset creation', () => __awaiter(void 0, void 0, void 0, function* () {
        const rawValue = mocks_1.dsMockUtils.createMockBytes('something');
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
            customTypeData: {
                id: mocks_1.dsMockUtils.createMockU32(),
                rawValue,
            },
            status: types_2.TickerReservationStatus.Reserved,
        });
        const registerAssetTypeTx = mocks_1.dsMockUtils.createTxStub('asset', 'registerCustomAssetType');
        const createTokenTx = mocks_1.dsMockUtils.createTxStub('asset', 'createAsset');
        const newCustomType = mocks_1.dsMockUtils.createMockAssetType({
            Custom: mocks_1.dsMockUtils.createMockU32(10),
        });
        addTransactionStub
            .withArgs(registerAssetTypeTx, sinon_1.default.match.object, rawValue)
            .returns([newCustomType]);
        const result = yield createSecurityToken_1.prepareCreateSecurityToken.call(proc, args);
        sinon_1.default.assert.calledWith(addTransactionStub, registerAssetTypeTx, sinon_1.default.match.object, rawValue);
        sinon_1.default.assert.calledWith(addTransactionStub, createTokenTx, sinon_1.default.match.any, sinon_1.default.match.any, sinon_1.default.match.any, sinon_1.default.match.any, newCustomType, sinon_1.default.match.any, sinon_1.default.match.any, sinon_1.default.match.any);
        expect(result).toMatchObject(mocks_1.entityMockUtils.getSecurityTokenInstance({ ticker }));
    }));
    describe('createRegisterCustomAssetTypeResolver', () => {
        const filterEventRecordsStub = sinon_1.default.stub(utilsInternalModule, 'filterEventRecords');
        const id = new bignumber_js_1.default(1);
        const rawId = mocks_1.dsMockUtils.createMockU32(id.toNumber());
        const rawValue = mocks_1.dsMockUtils.createMockBytes('something');
        beforeEach(() => {
            filterEventRecordsStub.returns([
                mocks_1.dsMockUtils.createMockIEvent([
                    mocks_1.dsMockUtils.createMockIdentityId('someDid'),
                    rawId,
                    rawValue,
                ]),
            ]);
        });
        afterEach(() => {
            filterEventRecordsStub.reset();
        });
        test('should return the new custom AssetType', () => {
            const fakeResult = 'assetType';
            internalTokenTypeToAssetTypeStub.withArgs({ Custom: rawId }, mockContext).returns(fakeResult);
            const result = createSecurityToken_1.createRegisterCustomAssetTypeResolver(mockContext)({});
            expect(result).toBe(fakeResult);
        });
    });
    describe('getAuthorization', () => {
        test('should return the appropriate roles and permissions', () => __awaiter(void 0, void 0, void 0, function* () {
            let proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
                customTypeData: null,
                status: types_2.TickerReservationStatus.Reserved,
            });
            let boundFunc = createSecurityToken_1.getAuthorization.bind(proc);
            let result = yield boundFunc(args);
            expect(result).toEqual({
                roles: [{ type: types_2.RoleType.TickerOwner, ticker }],
                permissions: {
                    tokens: [],
                    portfolios: [],
                    transactions: [types_1.TxTags.asset.CreateAsset],
                },
            });
            proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
                customTypeData: {
                    id: mocks_1.dsMockUtils.createMockU32(),
                    rawValue: mocks_1.dsMockUtils.createMockBytes('something'),
                },
                status: types_2.TickerReservationStatus.Reserved,
            });
            boundFunc = createSecurityToken_1.getAuthorization.bind(proc);
            result = yield boundFunc(Object.assign(Object.assign({}, args), { documents: [{ uri: 'www.doc.com', name: 'myDoc' }] }));
            expect(result).toEqual({
                roles: [{ type: types_2.RoleType.TickerOwner, ticker }],
                permissions: {
                    tokens: [],
                    portfolios: [],
                    transactions: [
                        types_1.TxTags.asset.CreateAsset,
                        types_1.TxTags.asset.AddDocuments,
                        types_1.TxTags.asset.RegisterCustomAssetType,
                    ],
                },
            });
            proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
                customTypeData: {
                    id: mocks_1.dsMockUtils.createMockU32(10),
                    rawValue: mocks_1.dsMockUtils.createMockBytes('something'),
                },
                status: types_2.TickerReservationStatus.Reserved,
            });
            boundFunc = createSecurityToken_1.getAuthorization.bind(proc);
            result = yield boundFunc(Object.assign(Object.assign({}, args), { documents: [] }));
            expect(result).toEqual({
                roles: [{ type: types_2.RoleType.TickerOwner, ticker }],
                permissions: {
                    tokens: [],
                    portfolios: [],
                    transactions: [types_1.TxTags.asset.CreateAsset],
                },
            });
            proc = mocks_1.procedureMockUtils.getInstance(mockContext, {
                customTypeData: {
                    id: mocks_1.dsMockUtils.createMockU32(10),
                    rawValue: mocks_1.dsMockUtils.createMockBytes('something'),
                },
                status: types_2.TickerReservationStatus.Free,
            });
            boundFunc = createSecurityToken_1.getAuthorization.bind(proc);
            result = yield boundFunc(Object.assign(Object.assign({}, args), { documents: [], reservationRequired: false }));
            expect(result).toEqual({
                permissions: {
                    tokens: [],
                    portfolios: [],
                    transactions: [types_1.TxTags.asset.CreateAsset],
                },
            });
        }));
    });
    describe('prepareStorage', () => {
        test('should return the custom asset type ID and bytes representation along with ticker reservation status', () => __awaiter(void 0, void 0, void 0, function* () {
            const proc = mocks_1.procedureMockUtils.getInstance(mockContext);
            const boundFunc = createSecurityToken_1.prepareStorage.bind(proc);
            mocks_1.entityMockUtils.getTickerReservationDetailsStub().resolves({
                owner: mocks_1.entityMockUtils.getIdentityInstance(),
                expiryDate: null,
                status: types_2.TickerReservationStatus.Reserved,
            });
            let result = yield boundFunc({ tokenType: types_2.KnownTokenType.EquityCommon });
            expect(result).toEqual({
                customTypeData: null,
                status: types_2.TickerReservationStatus.Reserved,
            });
            const rawValue = mocks_1.dsMockUtils.createMockBytes('something');
            sinon_1.default
                .stub(utilsConversionModule, 'stringToBytes')
                .withArgs('something', mockContext)
                .returns(rawValue);
            let id = mocks_1.dsMockUtils.createMockU32();
            const customTypesStub = mocks_1.dsMockUtils.createQueryStub('asset', 'customTypesInverse', {
                returnValue: id,
            });
            result = yield boundFunc({ tokenType: 'something' });
            expect(result).toEqual({
                customTypeData: {
                    rawValue,
                    id,
                },
                status: types_2.TickerReservationStatus.Reserved,
            });
            id = mocks_1.dsMockUtils.createMockU32(10);
            customTypesStub.resolves(id);
            result = yield boundFunc({ tokenType: 'something' });
            expect(result).toEqual({
                customTypeData: {
                    rawValue,
                    id,
                },
                status: types_2.TickerReservationStatus.Reserved,
            });
        }));
    });
});
//# sourceMappingURL=createSecurityToken.js.map