"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 moveFunds_1 = require("../moveFunds");
const procedureUtilsModule = __importStar(require("../utils"));
const internal_1 = require("../../../internal");
const mocks_1 = require("../../../testUtils/mocks");
const types_2 = require("../../../types");
const utilsConversionModule = __importStar(require("../../../utils/conversion"));
jest.mock('~/api/entities/NumberedPortfolio', require("../../../testUtils/mocks/entities").mockNumberedPortfolioModule('~/api/entities/NumberedPortfolio'));
jest.mock('~/api/entities/DefaultPortfolio', require("../../../testUtils/mocks/entities").mockDefaultPortfolioModule('~/api/entities/DefaultPortfolio'));
describe('moveFunds procedure', () => {
    let mockContext;
    let portfolioIdToMeshPortfolioIdStub;
    let portfolioMovementToMovePortfolioItemStub;
    let portfolioLikeToPortfolioIdStub;
    let assertPortfolioExistsStub;
    beforeAll(() => {
        mocks_1.dsMockUtils.initMocks();
        mocks_1.procedureMockUtils.initMocks();
        mocks_1.entityMockUtils.initMocks();
        portfolioIdToMeshPortfolioIdStub = sinon_1.default.stub(utilsConversionModule, 'portfolioIdToMeshPortfolioId');
        portfolioMovementToMovePortfolioItemStub = sinon_1.default.stub(utilsConversionModule, 'portfolioMovementToMovePortfolioItem');
        portfolioLikeToPortfolioIdStub = sinon_1.default.stub(utilsConversionModule, 'portfolioLikeToPortfolioId');
        assertPortfolioExistsStub = sinon_1.default.stub(procedureUtilsModule, 'assertPortfolioExists');
    });
    beforeEach(() => {
        mockContext = mocks_1.dsMockUtils.getContextInstance();
        mocks_1.entityMockUtils.configureMocks({
            numberedPortfolioOptions: {
                isOwnedBy: true,
            },
        });
        assertPortfolioExistsStub.returns(true);
    });
    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 both portfolios do not have the same owner', () => {
        const fromId = new bignumber_js_1.default(1);
        const fromDid = 'someDid';
        const toId = new bignumber_js_1.default(2);
        const toDid = 'otherDid';
        const fromPortfolio = new internal_1.NumberedPortfolio({ id: fromId, did: fromDid }, mockContext);
        const toPortfolio = mocks_1.entityMockUtils.getNumberedPortfolioInstance({
            id: toId,
            did: toDid,
        });
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext);
        portfolioLikeToPortfolioIdStub.withArgs(fromPortfolio).returns({ did: fromDid, number: toId });
        portfolioLikeToPortfolioIdStub.withArgs(toPortfolio).returns({ did: toDid, number: toId });
        return expect(moveFunds_1.prepareMoveFunds.call(proc, {
            from: fromPortfolio,
            to: toPortfolio,
            items: [],
        })).rejects.toThrow('Both portfolios should have the same owner');
    });
    test('should throw an error if both portfolios are the same', () => {
        const id = new bignumber_js_1.default(1);
        const did = 'someDid';
        const samePortfolio = new internal_1.NumberedPortfolio({ id, did }, mockContext);
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext);
        const fakePortfolioId = { did, number: id };
        portfolioLikeToPortfolioIdStub.withArgs(samePortfolio).returns(fakePortfolioId);
        portfolioLikeToPortfolioIdStub.withArgs(samePortfolio).returns(fakePortfolioId);
        return expect(moveFunds_1.prepareMoveFunds.call(proc, {
            from: samePortfolio,
            to: samePortfolio,
            items: [],
        })).rejects.toThrow('Origin and destination should be different Portfolios');
    });
    test('should throw an error if some of the amount token to move exceed its balance', () => __awaiter(void 0, void 0, void 0, function* () {
        const fromId = new bignumber_js_1.default(1);
        const toId = new bignumber_js_1.default(2);
        const fromDid = 'someDid';
        const toDid = 'otherDid';
        const from = new internal_1.NumberedPortfolio({ id: fromId, did: fromDid }, mockContext);
        const to = new internal_1.NumberedPortfolio({ id: toId, did: toDid }, mockContext);
        const securityToken01 = new internal_1.SecurityToken({ ticker: 'TICKER001' }, mockContext);
        const securityToken02 = new internal_1.SecurityToken({ ticker: 'TICKER002' }, mockContext);
        const items = [
            {
                token: securityToken01.ticker,
                amount: new bignumber_js_1.default(100),
            },
            {
                token: securityToken02,
                amount: new bignumber_js_1.default(20),
            },
        ];
        portfolioLikeToPortfolioIdStub.withArgs(from).returns({ did: fromDid, number: fromId });
        portfolioLikeToPortfolioIdStub.withArgs(to).returns({ did: toDid, number: toId });
        mocks_1.entityMockUtils.configureMocks({
            numberedPortfolioOptions: {
                tokenBalances: [
                    { token: securityToken01, free: new bignumber_js_1.default(50) },
                    { token: securityToken02, free: new bignumber_js_1.default(10) },
                ],
            },
        });
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext);
        let error;
        try {
            yield moveFunds_1.prepareMoveFunds.call(proc, {
                from,
                to,
                items,
            });
        }
        catch (err) {
            error = err;
        }
        expect(error.message).toBe("Some of the amounts being transferred exceed the Portfolio's balance");
        expect(error.data.balanceExceeded).toMatchObject(items);
    }));
    test('should add a move portfolio funds transaction to the queue', () => __awaiter(void 0, void 0, void 0, function* () {
        const fromId = new bignumber_js_1.default(1);
        const toId = new bignumber_js_1.default(2);
        const did = 'someDid';
        const from = new internal_1.NumberedPortfolio({ id: fromId, did }, mockContext);
        const to = new internal_1.NumberedPortfolio({ id: toId, did }, mockContext);
        const securityToken = new internal_1.SecurityToken({ ticker: 'TICKER001' }, mockContext);
        const items = [
            {
                token: securityToken.ticker,
                amount: new bignumber_js_1.default(100),
            },
        ];
        mocks_1.entityMockUtils.configureMocks({
            numberedPortfolioOptions: {
                did,
                tokenBalances: [{ token: securityToken, total: new bignumber_js_1.default(150) }],
            },
            defaultPortfolioOptions: {
                did,
                tokenBalances: [{ token: securityToken, total: new bignumber_js_1.default(150) }],
            },
        });
        let fromPortfolioId = { did, number: fromId };
        let toPortfolioId = { did, number: toId };
        portfolioLikeToPortfolioIdStub.withArgs(from).returns(fromPortfolioId);
        portfolioLikeToPortfolioIdStub.withArgs(to).returns(toPortfolioId);
        let rawFromMeshPortfolioId = mocks_1.dsMockUtils.createMockPortfolioId({
            did: mocks_1.dsMockUtils.createMockIdentityId(did),
            kind: mocks_1.dsMockUtils.createMockPortfolioKind({
                User: mocks_1.dsMockUtils.createMockU64(fromId.toNumber()),
            }),
        });
        portfolioIdToMeshPortfolioIdStub
            .withArgs(fromPortfolioId, mockContext)
            .returns(rawFromMeshPortfolioId);
        let rawToMeshPortfolioId = mocks_1.dsMockUtils.createMockPortfolioId({
            did: mocks_1.dsMockUtils.createMockIdentityId(did),
            kind: mocks_1.dsMockUtils.createMockPortfolioKind({
                User: mocks_1.dsMockUtils.createMockU64(toId.toNumber()),
            }),
        });
        portfolioIdToMeshPortfolioIdStub
            .withArgs(toPortfolioId, mockContext)
            .returns(rawToMeshPortfolioId);
        const rawMovePortfolioItem = mocks_1.dsMockUtils.createMockMovePortfolioItem({
            ticker: mocks_1.dsMockUtils.createMockTicker(items[0].token),
            amount: mocks_1.dsMockUtils.createMockBalance(items[0].amount.toNumber()),
        });
        portfolioMovementToMovePortfolioItemStub
            .withArgs(items[0], mockContext)
            .returns(rawMovePortfolioItem);
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext);
        const transaction = mocks_1.dsMockUtils.createTxStub('portfolio', 'movePortfolioFunds');
        yield moveFunds_1.prepareMoveFunds.call(proc, {
            from,
            to: toId,
            items,
        });
        let addTransactionStub = mocks_1.procedureMockUtils.getAddTransactionStub();
        sinon_1.default.assert.calledWith(addTransactionStub, transaction, {}, rawFromMeshPortfolioId, rawToMeshPortfolioId, [rawMovePortfolioItem]);
        const defaultTo = new internal_1.DefaultPortfolio({ did }, mockContext);
        toPortfolioId = { did };
        portfolioLikeToPortfolioIdStub.withArgs(defaultTo).returns(toPortfolioId);
        rawToMeshPortfolioId = mocks_1.dsMockUtils.createMockPortfolioId({
            did: mocks_1.dsMockUtils.createMockIdentityId(did),
            kind: mocks_1.dsMockUtils.createMockPortfolioKind('Default'),
        });
        portfolioIdToMeshPortfolioIdStub
            .withArgs(toPortfolioId, mockContext)
            .returns(rawToMeshPortfolioId);
        yield moveFunds_1.prepareMoveFunds.call(proc, {
            from,
            items,
        });
        addTransactionStub = mocks_1.procedureMockUtils.getAddTransactionStub();
        sinon_1.default.assert.calledWith(addTransactionStub, transaction, {}, rawFromMeshPortfolioId, rawToMeshPortfolioId, [rawMovePortfolioItem]);
        const defaultFrom = new internal_1.DefaultPortfolio({ did }, mockContext);
        fromPortfolioId = { did };
        toPortfolioId = { did, number: toId };
        portfolioLikeToPortfolioIdStub.withArgs(defaultFrom).returns(fromPortfolioId);
        portfolioLikeToPortfolioIdStub.withArgs(to).returns(toPortfolioId);
        rawFromMeshPortfolioId = mocks_1.dsMockUtils.createMockPortfolioId({
            did: mocks_1.dsMockUtils.createMockIdentityId(did),
            kind: mocks_1.dsMockUtils.createMockPortfolioKind('Default'),
        });
        portfolioIdToMeshPortfolioIdStub
            .withArgs(fromPortfolioId, mockContext)
            .returns(rawFromMeshPortfolioId);
        rawToMeshPortfolioId = mocks_1.dsMockUtils.createMockPortfolioId({
            did: mocks_1.dsMockUtils.createMockIdentityId(did),
            kind: mocks_1.dsMockUtils.createMockPortfolioKind({
                User: mocks_1.dsMockUtils.createMockU64(toId.toNumber()),
            }),
        });
        portfolioIdToMeshPortfolioIdStub
            .withArgs(toPortfolioId, mockContext)
            .returns(rawToMeshPortfolioId);
        yield moveFunds_1.prepareMoveFunds.call(proc, {
            from: defaultFrom,
            to,
            items,
        });
        addTransactionStub = mocks_1.procedureMockUtils.getAddTransactionStub();
        sinon_1.default.assert.calledWith(addTransactionStub, transaction, {}, rawFromMeshPortfolioId, rawToMeshPortfolioId, [rawMovePortfolioItem]);
    }));
    describe('getAuthorization', () => {
        test('should return the appropriate roles and permissions', () => {
            const proc = mocks_1.procedureMockUtils.getInstance(mockContext);
            const boundFunc = moveFunds_1.getAuthorization.bind(proc);
            const fromId = new bignumber_js_1.default(1);
            const toId = new bignumber_js_1.default(10);
            const did = 'someDid';
            let from = new internal_1.NumberedPortfolio({ id: fromId, did }, mockContext);
            const toPortfolio = new internal_1.NumberedPortfolio({ did, id: toId }, mockContext);
            let args = {
                from,
            };
            let portfolioId = { did, number: fromId };
            expect(boundFunc(args)).toEqual({
                roles: [{ type: types_2.RoleType.PortfolioCustodian, portfolioId }],
                permissions: {
                    transactions: [types_1.TxTags.portfolio.MovePortfolioFunds],
                    portfolios: [from, new internal_1.DefaultPortfolio({ did }, mockContext)],
                    tokens: [],
                },
            });
            from = new internal_1.DefaultPortfolio({ did }, mockContext);
            args = {
                from,
                to: toId,
            };
            portfolioId = { did };
            expect(boundFunc(args)).toEqual({
                roles: [{ type: types_2.RoleType.PortfolioCustodian, portfolioId }],
                permissions: {
                    transactions: [types_1.TxTags.portfolio.MovePortfolioFunds],
                    portfolios: [from, toPortfolio],
                    tokens: [],
                },
            });
            args = {
                from,
                to: toPortfolio,
            };
            portfolioId = { did };
            expect(boundFunc(args)).toEqual({
                roles: [{ type: types_2.RoleType.PortfolioCustodian, portfolioId }],
                permissions: {
                    transactions: [types_1.TxTags.portfolio.MovePortfolioFunds],
                    portfolios: [from, toPortfolio],
                    tokens: [],
                },
            });
        });
    });
});
//# sourceMappingURL=moveFunds.js.map