"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());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const api_1 = require("@polkadot/api");
const chai_1 = require("chai");
const bn_js_1 = __importDefault(require("bn.js"));
const big_js_1 = __importDefault(require("big.js"));
const factory_1 = require("../../../../../src/factory");
const config_1 = require("../../../../config");
const src_1 = require("../../../../../src");
const storage_1 = require("../../../../../src/utils/storage");
const helpers_1 = require("../../../../utils/helpers");
describe("escrow", () => {
    let api;
    let interBtcAPI;
    let userAccount_1;
    let userAccount_2;
    let userAccount_3;
    let sudoAccount;
    let governanceCurrency;
    before(function () {
        return __awaiter(this, void 0, void 0, function* () {
            const keyring = new api_1.Keyring({ type: "sr25519" });
            api = yield factory_1.createSubstrateAPI(config_1.PARACHAIN_ENDPOINT);
            // Use vault accounts as they are not involved in other tests but are prefunded with governance tokens
            userAccount_1 = keyring.addFromUri(config_1.VAULT_3_URI);
            userAccount_2 = keyring.addFromUri(config_1.VAULT_TO_LIQUIDATE_URI);
            userAccount_3 = keyring.addFromUri(config_1.VAULT_TO_BAN_URI);
            sudoAccount = keyring.addFromUri(config_1.SUDO_URI);
            interBtcAPI = new src_1.DefaultInterBtcApi(api, "regtest", userAccount_1, config_1.ESPLORA_BASE_PATH);
            governanceCurrency = interBtcAPI.getGovernanceCurrency();
        });
    });
    after(() => __awaiter(void 0, void 0, void 0, function* () {
        api.disconnect();
    }));
    // PRECONDITION: This test must run first, so no tokens are locked.
    it("Non-negative voting supply", () => __awaiter(void 0, void 0, void 0, function* () {
        const totalVotingSupply = yield interBtcAPI.escrow.totalVotingSupply();
        chai_1.assert.equal(totalVotingSupply.toString(), "0", "Voting supply balance should be zero before any tokens are locked");
    })).timeout(100000);
    // PRECONDITION: This test must run second, so no tokens are locked.
    it("should return 0 reward and apy estimate", () => __awaiter(void 0, void 0, void 0, function* () {
        const rewardsEstimate = yield interBtcAPI.escrow.getRewardEstimate(src_1.newAccountId(api, userAccount_1.address));
        const expected = new big_js_1.default(0);
        chai_1.assert.isTrue(expected.eq(rewardsEstimate.apy), `APY should be 0, but is ${rewardsEstimate.apy.toString()}`);
        chai_1.assert.isTrue(rewardsEstimate.amount.isZero(), `Rewards should be 0, but are ${rewardsEstimate.amount.toHuman()}`);
    }));
    it("should compute voting balance, total supply, and total staked balance", () => __awaiter(void 0, void 0, void 0, function* () {
        const user1_intrAmount = src_1.newMonetaryAmount(100, governanceCurrency, true);
        const user2_intrAmount = src_1.newMonetaryAmount(60, governanceCurrency, true);
        const chargedFees = src_1.newMonetaryAmount(2, governanceCurrency, true);
        const currentBlockNumber = yield interBtcAPI.system.getCurrentBlockNumber();
        const unlockHeightDiff = (yield interBtcAPI.escrow.getSpan()).toNumber();
        const userIntrPairs = [
            [userAccount_1, user1_intrAmount],
            [userAccount_2, user2_intrAmount],
        ];
        const stakedTotalBefore = yield interBtcAPI.escrow.getTotalStakedBalance();
        // FIXME: remove magic multiplier
        for (const [userKeyring, amount] of userIntrPairs) {
            const userAccount = src_1.newAccountId(api, userKeyring.address);
            const existingBalance = yield interBtcAPI.tokens.balance(governanceCurrency, userAccount);
            yield helpers_1.sudo(interBtcAPI, () => interBtcAPI.tokens.setBalance(userAccount, amount.mul(2).add(chargedFees.mul(3)).add(existingBalance.free), existingBalance.reserved));
        }
        interBtcAPI.setAccount(userAccount_1);
        yield interBtcAPI.escrow.createLock(user1_intrAmount, currentBlockNumber + unlockHeightDiff);
        const votingBalance = yield interBtcAPI.escrow.votingBalance(src_1.newAccountId(api, userAccount_1.address), currentBlockNumber + 0.4 * unlockHeightDiff);
        const votingSupply = yield interBtcAPI.escrow.totalVotingSupply(currentBlockNumber + 0.4 * unlockHeightDiff);
        chai_1.assert.equal(votingBalance.toString(), votingSupply.toString());
        // Hardcoded value here to match the parachain
        chai_1.assert.equal(votingSupply.toBig().round(2, 0 /* RoundDown */).toString(), "0.62");
        const firstYearRewards = 125000000000000000;
        const blocksPerYear = 5256000;
        yield storage_1.setNumericStorage(api, "EscrowAnnuity", "RewardPerBlock", new bn_js_1.default(firstYearRewards / blocksPerYear), sudoAccount, 128);
        const rewardsEstimate = yield interBtcAPI.escrow.getRewardEstimate(src_1.newAccountId(api, userAccount_1.address));
        const expectedRewards = src_1.newMonetaryAmount((firstYearRewards / blocksPerYear) * unlockHeightDiff, interBtcAPI.getGovernanceCurrency());
        chai_1.assert.isTrue(expectedRewards.toBig().div(rewardsEstimate.amount.toBig()).lt(1.1) &&
            expectedRewards.toBig().div(rewardsEstimate.amount.toBig()).gt(0.9), "The estimate should be within 10% of the actual first year rewards");
        chai_1.assert.isTrue(rewardsEstimate.apy.gte(100), `Expected more than 100% APY, got ${rewardsEstimate.apy.toString()}`);
        // Lock the tokens of a second user, to ensure total voting supply is still correct
        interBtcAPI.setAccount(userAccount_2);
        yield interBtcAPI.escrow.createLock(user2_intrAmount, currentBlockNumber + unlockHeightDiff);
        const votingSupplyAfterSecondUser = yield interBtcAPI.escrow.totalVotingSupply(currentBlockNumber + 0.4 * unlockHeightDiff);
        chai_1.assert.equal(votingSupplyAfterSecondUser.toBig().round(2, 0 /* RoundDown */).toString(), "0.99");
        const stakedTotalAfter = yield interBtcAPI.escrow.getTotalStakedBalance();
        const lockedBalanceTotal = user1_intrAmount.add(user2_intrAmount);
        const expectedNewBalance = stakedTotalBefore.add(lockedBalanceTotal);
        chai_1.assert.isTrue(stakedTotalAfter.eq(expectedNewBalance), `Expected total staked balance to have increased by locked amounts: ${lockedBalanceTotal.toHuman()},
            but old balance was ${stakedTotalBefore.toHuman()} and new balance is ${stakedTotalAfter.toHuman()}`);
    })).timeout(15 * 60000);
    // TODO: Unskip and implement once instant-seal is added to interbtc-standalone. Otherwise this test would take a week.
    // it.skip("should withdraw locked funds", async () => {}).timeout(100000);
    it("should increase amount and unlock height", () => __awaiter(void 0, void 0, void 0, function* () {
        const user_intrAmount = src_1.newMonetaryAmount(1000, governanceCurrency, true);
        const userAccount = src_1.newAccountId(api, userAccount_3.address);
        const chargedFees = src_1.newMonetaryAmount(2, governanceCurrency, true);
        const currentBlockNumber = yield interBtcAPI.system.getCurrentBlockNumber();
        const unlockHeightDiff = (yield interBtcAPI.escrow.getSpan()).toNumber();
        // FIXME: remove magic multiplier
        yield helpers_1.sudo(interBtcAPI, () => interBtcAPI.tokens.setBalance(userAccount, user_intrAmount.mul(2).add(chargedFees.mul(3))));
        interBtcAPI.setAccount(userAccount_3);
        yield interBtcAPI.escrow.createLock(user_intrAmount, currentBlockNumber + unlockHeightDiff);
        yield interBtcAPI.escrow.increaseAmount(user_intrAmount);
        yield interBtcAPI.escrow.increaseUnlockHeight(currentBlockNumber + unlockHeightDiff + unlockHeightDiff);
    })).timeout(200000);
});
//# sourceMappingURL=escrow.test.js.map