"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 });
const api_1 = require("@polkadot/api");
const index_1 = require("../../../../../src/index");
const factory_1 = require("../../../../../src/factory");
const chai_1 = require("../../../../chai");
const config_1 = require("../../../../config");
const bitcoin_core_client_1 = require("../../../../../src/utils/bitcoin-core-client");
const issueRedeem_1 = require("../../../../../src/utils/issueRedeem");
const src_1 = require("../../../../../src");
const helpers_1 = require("../../../../utils/helpers");
describe("issue", () => {
    let api;
    let bitcoinCoreClient;
    let keyring;
    let userInterBtcAPI;
    let userAccount;
    let vault_1;
    let vault_1_ids;
    let vault_2;
    let vault_2_ids;
    let wrappedCurrency;
    let collateralCurrencies;
    before(function () {
        return __awaiter(this, void 0, void 0, function* () {
            api = yield factory_1.createSubstrateAPI(config_1.PARACHAIN_ENDPOINT);
            keyring = new api_1.Keyring({ type: "sr25519" });
            userAccount = keyring.addFromUri(config_1.USER_1_URI);
            userInterBtcAPI = new index_1.DefaultInterBtcApi(api, "regtest", userAccount, config_1.ESPLORA_BASE_PATH);
            collateralCurrencies = helpers_1.getCorrespondingCollateralCurrenciesForTests(userInterBtcAPI.getGovernanceCurrency());
            wrappedCurrency = userInterBtcAPI.getWrappedCurrency();
            vault_1 = keyring.addFromUri(config_1.VAULT_1_URI);
            vault_2 = keyring.addFromUri(config_1.VAULT_2_URI);
            vault_1_ids = collateralCurrencies.map((collateralCurrency) => src_1.newVaultId(api, vault_1.address, collateralCurrency, wrappedCurrency));
            vault_2_ids = collateralCurrencies.map((collateralCurrency) => src_1.newVaultId(api, vault_2.address, collateralCurrency, wrappedCurrency));
            bitcoinCoreClient = new bitcoin_core_client_1.BitcoinCoreClient(config_1.BITCOIN_CORE_NETWORK, config_1.BITCOIN_CORE_HOST, config_1.BITCOIN_CORE_USERNAME, config_1.BITCOIN_CORE_PASSWORD, config_1.BITCOIN_CORE_PORT, config_1.BITCOIN_CORE_WALLET);
        });
    });
    after(() => __awaiter(void 0, void 0, void 0, function* () {
        api.disconnect();
    }));
    it("should request one issue", () => __awaiter(void 0, void 0, void 0, function* () {
        // may fail if the relay isn't fully initialized
        const amount = index_1.newMonetaryAmount(0.0001, wrappedCurrency, true);
        const feesToPay = yield userInterBtcAPI.issue.getFeesToPay(amount);
        const requestResults = yield userInterBtcAPI.issue.request(amount);
        chai_1.assert.equal(requestResults.length, 1, "Created multiple requests instead of one (ensure vault has sufficient collateral)");
        const requestResult = requestResults[0];
        const issueRequest = yield userInterBtcAPI.issue.getRequestById(requestResult.id);
        chai_1.assert.equal(issueRequest.wrappedAmount.toString(), amount.sub(feesToPay).toString(), "Amount different than expected");
    }));
    it("should list existing requests", () => __awaiter(void 0, void 0, void 0, function* () {
        const issueRequests = yield userInterBtcAPI.issue.list();
        chai_1.assert.isAtLeast(issueRequests.length, 1, "Should have at least 1 issue request");
    }));
    // FIXME: not used at the moment. Fix in a more elegant way, i.e., check what is issuable
    // by two vaults can request exactly that amount instead of multiplying by 1.1
    it.skip("should batch request across several vaults", () => __awaiter(void 0, void 0, void 0, function* () {
        const requestLimits = yield userInterBtcAPI.issue.getRequestLimits();
        const amount = requestLimits.singleVaultMaxIssuable.mul(1.1);
        const issueRequests = yield userInterBtcAPI.issue.request(amount);
        chai_1.assert.equal(issueRequests.length, 2, "Created wrong amount of requests, vaults have insufficient collateral");
        const issuedAmount1 = issueRequests[0].wrappedAmount;
        const issueFee1 = issueRequests[0].bridgeFee;
        const issuedAmount2 = issueRequests[1].wrappedAmount;
        const issueFee2 = issueRequests[1].bridgeFee;
        chai_1.assert.equal(issuedAmount1.add(issueFee1).add(issuedAmount2).add(issueFee2).toBig().round(5).toString(), amount.toBig().round(5).toString(), "Issued amount is not equal to requested amount");
    }));
    // auto-execution tests may stall indefinitely, due to vault client inaction.
    // This will cause the testing pipeline to time out.
    // TODO: Discuss if we want to test this in the lib. Should rather be tested in the clients
    it.skip("should request and auto-execute issue", () => __awaiter(void 0, void 0, void 0, function* () {
        for (const vault_1_id of vault_1_ids) {
            const amount = index_1.newMonetaryAmount(0.00121, wrappedCurrency, true);
            const feesToPay = yield userInterBtcAPI.issue.getFeesToPay(amount);
            const issueResult = yield issueRedeem_1.issueSingle(userInterBtcAPI, bitcoinCoreClient, userAccount, amount, vault_1_id, true, false);
            chai_1.assert.equal(issueResult.finalWrappedTokenBalance.sub(issueResult.initialWrappedTokenBalance).toString(), amount.sub(feesToPay).toString(), "Final balance was not increased by the exact amount specified");
        }
    })).timeout(1000000);
    it("should request and manually execute issue", () => __awaiter(void 0, void 0, void 0, function* () {
        for (const vault_2_id of vault_2_ids) {
            const currencyTicker = (yield index_1.currencyIdToMonetaryCurrency(userInterBtcAPI.assetRegistry, vault_2_id.currencies.collateral)).ticker;
            const amount = index_1.newMonetaryAmount(0.00001, wrappedCurrency, true);
            const feesToPay = yield userInterBtcAPI.issue.getFeesToPay(amount);
            const oneSatoshi = index_1.newMonetaryAmount(1, wrappedCurrency, false);
            const issueResult = yield issueRedeem_1.issueSingle(userInterBtcAPI, bitcoinCoreClient, userAccount, amount, vault_2_id, false, false);
            // calculate expected final balance and round the fees value as the parachain will do so when calculating fees.
            const amtInSatoshi = amount.toBig(index_1.ATOMIC_UNIT);
            const feesInSatoshiRounded = feesToPay.toBig(index_1.ATOMIC_UNIT).round(0);
            const expectedFinalBalance = amtInSatoshi
                .sub(feesInSatoshiRounded)
                .sub(oneSatoshi.toBig(index_1.ATOMIC_UNIT))
                .toString();
            chai_1.assert.equal(issueResult.finalWrappedTokenBalance
                .sub(issueResult.initialWrappedTokenBalance)
                .toBig(index_1.ATOMIC_UNIT)
                .toString(), expectedFinalBalance, `Final balance was not increased by the exact amount specified (collateral: ${currencyTicker})`);
        }
    })).timeout(1000000);
    // TODO: maybe add this to issue API
    it("should get issueBtcDustValue", () => __awaiter(void 0, void 0, void 0, function* () {
        const dust = yield userInterBtcAPI.api.query.issue.issueBtcDustValue();
        chai_1.assert.equal(dust.toString(), "1000");
    }));
    it("should getFeesToPay", () => __awaiter(void 0, void 0, void 0, function* () {
        const amount = index_1.newMonetaryAmount(2, wrappedCurrency, true);
        const feesToPay = yield userInterBtcAPI.issue.getFeesToPay(amount);
        const feeRate = yield userInterBtcAPI.issue.getFeeRate();
        const expectedFeesInBTC = amount.toBig().toNumber() * feeRate.toNumber();
        // compare floating point values in BTC, allowing for small delta difference
        chai_1.assert.closeTo(feesToPay.toBig().toNumber(), expectedFeesInBTC, 0.00001, "Calculated fees in BTC do not match expectations");
    }));
    it("should getFeeRate", () => __awaiter(void 0, void 0, void 0, function* () {
        const feePercentage = yield userInterBtcAPI.issue.getFeeRate();
        chai_1.assert.equal(feePercentage.toString(), "0.0015");
    }));
    // FIXME: don't use magic numbers for these tests
    it("should getRequestLimits", () => __awaiter(void 0, void 0, void 0, function* () {
        const requestLimits = yield userInterBtcAPI.issue.getRequestLimits();
        const singleMaxIssuable = requestLimits.singleVaultMaxIssuable;
        const totalMaxIssuable = requestLimits.singleVaultMaxIssuable;
        const expected = index_1.newMonetaryAmount(0.0005, wrappedCurrency, true);
        chai_1.assert.isTrue(singleMaxIssuable.gt(expected), `singleVaultMaxIssuable is ${singleMaxIssuable.toHuman()}, expected greater than ${expected.toHuman()}`);
        chai_1.assert.isTrue(totalMaxIssuable.gte(singleMaxIssuable), `totalMaxIssuable is ${totalMaxIssuable.toHuman()}, expected greater than or equal to ${singleMaxIssuable.toHuman()}`);
    }));
    // TODO: Unskip after `subscribeToIssueExpiry` is reimplemented
    // This test should be kept at the end of the file as it will ban the vault used for issuing
    it.skip("should cancel an issue request", () => __awaiter(void 0, void 0, void 0, function* () {
        for (const vault_2_id of vault_2_ids) {
            yield helpers_1.runWhileMiningBTCBlocks(bitcoinCoreClient, () => __awaiter(void 0, void 0, void 0, function* () {
                const initialIssuePeriod = yield userInterBtcAPI.issue.getIssuePeriod();
                yield helpers_1.sudo(userInterBtcAPI, () => userInterBtcAPI.issue.setIssuePeriod(0));
                try {
                    // request issue
                    const amount = index_1.newMonetaryAmount(0.0000121, wrappedCurrency, true);
                    const vaultCollateral = yield index_1.currencyIdToMonetaryCurrency(userInterBtcAPI.assetRegistry, vault_2_id.currencies.collateral);
                    const requestResults = yield userInterBtcAPI.issue.request(amount, index_1.newAccountId(api, vault_2.address), vaultCollateral);
                    chai_1.assert.equal(requestResults.length, 1, "Test broken: more than one issue request created"); // sanity check
                    const requestResult = requestResults[0];
                    // Wait for issue expiry callback
                    // await new Promise<void>((resolve, _) => {
                    //     userInterBtcAPI.issue.subscribeToIssueExpiry(newAccountId(api, userAccount.address), (requestId) => {
                    //         if (stripHexPrefix(requestResult.id.toString()) === stripHexPrefix(requestId.toString())) {
                    //             resolve();
                    //         }
                    //     });
                    // });
                    yield userInterBtcAPI.issue.cancel(requestResult.id);
                    const issueRequest = yield userInterBtcAPI.issue.getRequestById(requestResult.id);
                    chai_1.assert.isTrue(issueRequest.status === index_1.IssueStatus.Cancelled, "Failed to cancel issue request");
                    // Set issue period back to its initial value to minimize side effects.
                    yield helpers_1.sudo(userInterBtcAPI, () => userInterBtcAPI.issue.setIssuePeriod(initialIssuePeriod));
                }
                catch (e) {
                    // Set issue period back to its initial value to minimize side effects.
                    yield helpers_1.sudo(userInterBtcAPI, () => userInterBtcAPI.issue.setIssuePeriod(initialIssuePeriod));
                    throw e;
                }
            }));
        }
    })).timeout(10 * 60000);
});
//# sourceMappingURL=issue.test.js.map