"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 });
/* eslint @typescript-eslint/no-var-requires: "off" */
const monetary_js_1 = require("@interlay/monetary-js");
const api_1 = require("@polkadot/api");
const util_crypto_1 = require("@polkadot/util-crypto");
const big_js_1 = __importDefault(require("big.js"));
const __1 = require("../..");
const config_1 = require("../../../test/config");
const helpers_1 = require("../../../test/utils/helpers");
const factory_1 = require("../../factory");
const encoding_1 = require("../encoding");
const yargs = require("yargs/yargs");
const { hideBin } = require("yargs/helpers");
let vault_1;
let sudoAccount;
const getCurrencyFromSymbol = (symbol) => {
    if (!Object.values(__1.CurrencyIdLiteral).includes(symbol)) {
        throw new Error(`Unknown currency symbol: ${symbol}`);
    }
    switch (symbol) {
        case "KSM":
            return monetary_js_1.Kusama;
        case "KBTC":
            return monetary_js_1.KBtc;
        case "KINT":
            return monetary_js_1.Kintsugi;
        case "DOT":
            return monetary_js_1.Polkadot;
        case "IBTC":
            return monetary_js_1.InterBtc;
        default:
        case "INTR":
            return monetary_js_1.Interlay;
    }
};
const setStorageAtKey = (api, key, data) => __awaiter(void 0, void 0, void 0, function* () {
    const tx = api.tx.sudo.sudo(api.tx.system.setStorage([[key, data]]));
    yield __1.DefaultTransactionAPI.sendLogged(api, sudoAccount, tx, undefined, true);
});
const setStorageAtKeyBatch = (api, newStorage) => __awaiter(void 0, void 0, void 0, function* () {
    const txs = newStorage.map((storage) => api.tx.sudo.sudo(api.tx.system.setStorage([storage])));
    const batchedTxs = api.tx.utility.batchAll(txs);
    yield __1.DefaultTransactionAPI.sendLogged(api, sudoAccount, batchedTxs, undefined, true);
});
const constructVaultId = (api, accountId, collateralCurrencySymbol, wrappedCurrencySymbol) => {
    const collateralCurrency = getCurrencyFromSymbol(collateralCurrencySymbol);
    const wrappedCurrency = getCurrencyFromSymbol(wrappedCurrencySymbol);
    const vaultId = encoding_1.newVaultId(api, accountId, collateralCurrency, wrappedCurrency);
    return vaultId;
};
const getVault = (api, vaultId) => __awaiter(void 0, void 0, void 0, function* () {
    const vaults = yield api.query.vaultRegistry.vaults.entries();
    const vault = vaults.find(vault => vault[1].value.id.eq(vaultId));
    if (vault === undefined) {
        throw new Error(`Vault not found, vault id: ${vaultId.toString()}`);
    }
    return vault;
});
const modifyVaultData = (api, vaultId, modifier) => __awaiter(void 0, void 0, void 0, function* () {
    const [storageKey, vaultData] = yield getVault(api, vaultId);
    const parsedVaultData = JSON.parse(JSON.stringify(vaultData));
    const modifiedVaultData = modifier(parsedVaultData);
    const storageData = api.createType("Option<VaultRegistryVault>", modifiedVaultData).toHex();
    console.log("Writing into vault storage...");
    yield setStorageAtKey(api, storageKey.toString(), storageData);
});
const disconnectApiOnExit = (api, callback) => (params) => __awaiter(void 0, void 0, void 0, function* () {
    yield callback(params);
    yield api.disconnect();
});
// Changes deposited collateral and issued tokens of the vault to allow premium redeem
const setPremiumRedeem = (interBtcApi) => disconnectApiOnExit(interBtcApi.api, ({ accountId, collateralSymbol, wrappedSymbol }) => __awaiter(void 0, void 0, void 0, function* () {
    const { api } = interBtcApi;
    const collateralCurrency = getCurrencyFromSymbol(collateralSymbol);
    const wrappedCurrency = getCurrencyFromSymbol(wrappedSymbol);
    const vaultId = encoding_1.newVaultId(api, accountId, collateralCurrency, wrappedCurrency);
    const oneBTC = "100000000";
    const parsedIssuedTokens = api.createType("u128", oneBTC);
    // Sets issued tokens amount to 1 BTC
    const newIssuedTokensAmount = __1.newMonetaryAmount(oneBTC, wrappedCurrency);
    const issuedTokensModifier = (vaultData) => (Object.assign(Object.assign({}, vaultData), { issuedTokens: parsedIssuedTokens }));
    console.log("Setting vault issued tokens to 1 BTC...");
    yield modifyVaultData(api, vaultId, issuedTokensModifier);
    // Sets vault backing collateral to average between premium redeem threshold and liquidation threshold
    const premiumRedeemThreshold = yield interBtcApi.vaults.getPremiumRedeemThreshold(collateralCurrency);
    const liquidationThreshold = yield interBtcApi.vaults.getLiquidationCollateralThreshold(collateralCurrency);
    const newCollateralizationRatio = premiumRedeemThreshold.add(liquidationThreshold).div(2);
    const newIssuedTokensInCollateralAmount = yield interBtcApi.oracle.convertWrappedToCurrency(newIssuedTokensAmount, collateralCurrency);
    const scalingFactor = new big_js_1.default(Math.pow(10, __1.FIXEDI128_SCALING_FACTOR));
    const newCollateralAmount = newIssuedTokensInCollateralAmount.toBig().mul(newCollateralizationRatio).mul(scalingFactor);
    const totalStakeDataHex = api.createType("u128", newCollateralAmount.toFixed()).toHex(true);
    const nonceHex = api.createType("u32", 0).toHex(); // 0 nonce by default
    const totalStakeStorageKey = __1.getStorageMapItemKey("VaultStaking", "TotalCurrentStake", nonceHex, vaultId.toHex());
    console.log("Setting backing collateral...");
    yield setStorageAtKey(api, totalStakeStorageKey, totalStakeDataHex);
    console.log(`OK: Vault collateralization ratio succesfully set to premium redeem value: ${newCollateralizationRatio.toString()}.`);
}));
const setLiquidationVault = ({ api }) => disconnectApiOnExit(api, ({ collateralSymbol, wrappedSymbol, toBeIssued, toBeRedeemed, issued, collateral }) => __awaiter(void 0, void 0, void 0, function* () {
    const collateralCurrency = getCurrencyFromSymbol(collateralSymbol);
    const wrappedCurrency = getCurrencyFromSymbol(wrappedSymbol);
    const currencyPair = encoding_1.newVaultCurrencyPair(api, collateralCurrency, wrappedCurrency);
    const storageKey = __1.getStorageMapItemKey("VaultRegistry", "LiquidationVault", currencyPair.toHex());
    const liquidationVault = {
        currencyPair,
        toBeIssuedTokens: api.createType("u128", toBeIssued),
        toBeRedeemedTokens: api.createType("u128", toBeRedeemed),
        issuedTokens: api.createType("u128", issued),
        collateral: api.createType("u128", collateral)
    };
    const storageData = api.createType("Option<VaultRegistrySystemVault>", liquidationVault).toHex();
    console.log(`Setting the liquidation vault for currency pair ${collateralSymbol}-${wrappedSymbol}...`);
    yield setStorageAtKey(api, storageKey, storageData);
    console.log("OK: Liquidation vault successfully set.");
}));
const setBalance = (interBtcApi) => disconnectApiOnExit(interBtcApi.api, ({ address, currencySymbol, value }) => __awaiter(void 0, void 0, void 0, function* () {
    const { api } = interBtcApi;
    console.log(`Setting ${currencySymbol} balance of ${address} to ${value}...`);
    const account = encoding_1.newAccountId(api, address);
    const currency = getCurrencyFromSymbol(currencySymbol);
    const amount = __1.newMonetaryAmount(value, currency);
    yield helpers_1.sudo(interBtcApi, () => __awaiter(void 0, void 0, void 0, function* () { return yield interBtcApi.tokens.setBalance(account, amount); }));
    console.log("OK: Balance successfully set.");
}));
const setVaultIssuedTokens = ({ api }) => disconnectApiOnExit(api, ({ accountId, collateralSymbol, wrappedSymbol, value }) => __awaiter(void 0, void 0, void 0, function* () {
    const vaultId = constructVaultId(api, accountId, collateralSymbol, wrappedSymbol);
    const parsedIssuedTokens = api.createType("u128", value);
    const modifier = (vaultData) => (Object.assign(Object.assign({}, vaultData), { issuedTokens: parsedIssuedTokens }));
    console.log(`Setting vault issued tokens to ${value}...`);
    yield modifyVaultData(api, vaultId, modifier);
    console.log("OK: Succesfully set vault issued tokens.");
}));
const setVaultBan = (interBtcApi) => disconnectApiOnExit(interBtcApi.api, ({ accountId, collateralSymbol, wrappedSymbol }) => __awaiter(void 0, void 0, void 0, function* () {
    const { api } = interBtcApi;
    const vaultId = constructVaultId(api, accountId, collateralSymbol, wrappedSymbol);
    const currentBlockNumber = yield interBtcApi.system.getCurrentBlockNumber();
    // Bans vault for the next 1000 blocks
    const newBannedUntil = api.createType("Option<u32>", currentBlockNumber + 1000);
    const modifier = (vaultData) => (Object.assign(Object.assign({}, vaultData), { bannedUntil: newBannedUntil }));
    console.log("Setting vault to be banned for the next 1,000 blocks...");
    yield modifyVaultData(api, vaultId, modifier);
    console.log(`OK: Succesfully banned vault until block ${newBannedUntil}.`);
}));
const setVaultUnban = ({ api }) => disconnectApiOnExit(api, ({ accountId, collateralSymbol, wrappedSymbol }) => __awaiter(void 0, void 0, void 0, function* () {
    const vaultId = constructVaultId(api, accountId, collateralSymbol, wrappedSymbol);
    const newBannedUntil = null;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const modifier = (vaultData) => (Object.assign(Object.assign({}, vaultData), { bannedUntil: newBannedUntil }));
    console.log("Setting vault to be unbanned...");
    yield modifyVaultData(api, vaultId, modifier);
    console.log("OK: Succesfully unbanned vault.");
}));
const fundVaultAccount = (interBtcApi) => disconnectApiOnExit(interBtcApi.api, ({ accountId, collateralSymbol }) => __awaiter(void 0, void 0, void 0, function* () {
    const newCollateralBalance = 10000000000000;
    console.log("Funding vault account with collateral token...");
    yield setBalance(interBtcApi)({ address: accountId, currencySymbol: collateralSymbol, value: newCollateralBalance });
}));
const setVaultReward = (interBtcApi) => disconnectApiOnExit(interBtcApi.api, ({ accountId, collateralSymbol, wrappedSymbol }) => __awaiter(void 0, void 0, void 0, function* () {
    const { api } = interBtcApi;
    const nonceHex = interBtcApi.api.createType("u32", 0).toHex();
    const vaultIdHex = constructVaultId(api, accountId, collateralSymbol, wrappedSymbol).toHex();
    const accountHex = api.createType("AccountId32", accountId).toHex();
    const rewardCurrencyHex = encoding_1.newCurrencyId(api, interBtcApi.getGovernanceCurrency()).toHex();
    const nonceVaultIdTupleHex = nonceHex + __1.stripHexPrefix(vaultIdHex);
    const nonceVaultIdAccountTupleHex = nonceVaultIdTupleHex + __1.stripHexPrefix(accountHex);
    const vaultIdAccountTupleHex = vaultIdHex + __1.stripHexPrefix(accountHex);
    // Global pool
    const globalRewardTallyStorageKey = __1.getStorageMapItemKey("VaultRewards", "RewardTally", rewardCurrencyHex, vaultIdHex);
    const globalRewardTallyData = "0x109da49d82b6fe2c4d740f50a4040000";
    const globalStakeStorageKey = __1.getStorageMapItemKey("VaultRewards", "Stake", vaultIdHex);
    const globalStakeData = "0x0000c0f26e1f724ad547030000000000";
    console.log("Writing into VaultRewards storage...");
    yield setStorageAtKeyBatch(interBtcApi.api, [
        [globalRewardTallyStorageKey, globalRewardTallyData],
        [globalStakeStorageKey, globalStakeData]
    ]);
    // Local pool
    const localRewardPerTokenStorageKey = __1.getStorageMapItemKey("VaultStaking", "RewardPerToken", rewardCurrencyHex, nonceVaultIdTupleHex);
    const localRewardPerTokenData = "0x2ea3f99f9a5c380d0000000000000000";
    const localRewardTallyStorageKey = __1.getStorageMapItemKey("VaultStaking", "RewardTally", rewardCurrencyHex, nonceVaultIdAccountTupleHex);
    const localRewardTallyData = "0xe0efbe1ff0a9ea7217f3dc0a3c000000";
    const localSlashPerTokenStorageKey = __1.getStorageMapItemKey("VaultStaking", "SlashPerToken", nonceHex, vaultIdHex);
    const localSlashPerTokenData = "0xcf149c9d789c05000000000000000000";
    const localSlashTallyStorageKey = __1.getStorageMapItemKey("VaultStaking", "SlashTally", nonceHex, vaultIdAccountTupleHex);
    const localSlashTallyData = "0xa62ed4024fa35e810e117c1900000000";
    const localStakeStorageKey = __1.getStorageMapItemKey("VaultStaking", "Stake", nonceHex, vaultIdAccountTupleHex);
    const localStakeData = "0x14b9f12a808c9588a5f278073f000000";
    const localTotalCurrentStakeStorageKey = __1.getStorageMapItemKey("VaultStaking", "TotalCurrentStake", nonceHex, vaultIdHex);
    const localTotalCurrentStakeData = "0x000000fed5929588a5f278073f000000";
    const localTotalRewardsStorageKey = __1.getStorageMapItemKey("VaultStaking", "TotalRewards", rewardCurrencyHex, nonceVaultIdTupleHex);
    const localTotalRewardsData = "0x000064a7b3b6e00d0000000000000000";
    const localTotalStakeStorageKey = __1.getStorageMapItemKey("VaultStaking", "TotalStake", nonceHex, vaultIdHex);
    const localTotalStakeData = "0x14b9f12a808c9588a5f278073f000000";
    console.log("Writing into VaultStaking storage...");
    yield setStorageAtKeyBatch(api, [
        [localRewardPerTokenStorageKey, localRewardPerTokenData],
        [localRewardTallyStorageKey, localRewardTallyData],
        [localSlashPerTokenStorageKey, localSlashPerTokenData],
        [localSlashTallyStorageKey, localSlashTallyData],
        [localStakeStorageKey, localStakeData],
        [localTotalCurrentStakeStorageKey, localTotalCurrentStakeData],
        [localTotalRewardsStorageKey, localTotalRewardsData],
        [localTotalStakeStorageKey, localTotalStakeData]
    ]);
    console.log("OK: Successfully set vault reward.");
}));
function main() {
    return __awaiter(this, void 0, void 0, function* () {
        console.log("Initializing crypto functions...");
        yield util_crypto_1.cryptoWaitReady();
        const keyring = new api_1.Keyring({ type: "sr25519" });
        vault_1 = keyring.addFromUri(config_1.VAULT_1_URI);
        sudoAccount = keyring.addFromUri(config_1.SUDO_URI);
        console.log("Connecting to parachain...");
        const api = yield factory_1.createSubstrateAPI(config_1.PARACHAIN_ENDPOINT);
        console.log("OK: Successfully connected to parachain.\n");
        const sudoAccountInterBtcApi = new __1.DefaultInterBtcApi(api, "regtest", sudoAccount, config_1.ESPLORA_BASE_PATH);
        const defaultVaultAccountId = vault_1.address;
        const defaultCollateralSymbol = (yield __1.currencyIdToMonetaryCurrency(sudoAccountInterBtcApi.assetRegistry, sudoAccountInterBtcApi.api.consts.currency.getRelayChainCurrencyId)).ticker;
        const defaultWrappedSymbol = sudoAccountInterBtcApi.getWrappedCurrency().ticker;
        console.log(`Default vault to use: ${defaultVaultAccountId}-${defaultCollateralSymbol}-${defaultWrappedSymbol}.\n`);
        const SET_VAULT_PARAMS_BASE = {
            accountId: {
                alias: "a",
                type: "string",
                demandOption: false,
                describe: "accountId of the vault",
                default: defaultVaultAccountId
            },
            collateralSymbol: {
                alias: "c",
                type: "string",
                demandOption: false,
                describe: "collateral currency symbol of the vault",
                default: defaultCollateralSymbol
            },
            wrappedSymbol: {
                alias: "w",
                type: "string",
                demandOption: false,
                describe: "wrapped currency symbol of the vault",
                default: defaultWrappedSymbol
            }
        };
        try {
            yield yargs(hideBin(process.argv))
                .command("balance", "Sets token balance of an account", {
                value: {
                    alias: "v",
                    type: "number",
                    demandOption: true,
                    describe: "new balance value"
                },
                currencySymbol: {
                    alias: "c",
                    type: "string",
                    demandOption: true,
                    describe: "currency symbol in which to set balance"
                },
                address: {
                    alias: "a",
                    type: "string",
                    demandOption: false,
                    describe: "address of which to set balance"
                }
            }, setBalance(sudoAccountInterBtcApi))
                .command("liquidationVault", "Sets system liquidation vault", {
                collateralSymbol: {
                    alias: "c",
                    type: "string",
                    demandOption: false,
                    describe: "collateral currency symbol of liquidation vault",
                    default: defaultCollateralSymbol
                },
                wrappedSymbol: {
                    alias: "w",
                    type: "string",
                    demandOption: false,
                    describe: "wrapped currency symbol of liquidation vault",
                    default: defaultWrappedSymbol
                },
                toBeIssued: {
                    type: "string",
                    demandOption: false,
                    default: "20000000",
                    describe: "toBeIssuedTokens value of liquidation vault"
                },
                issued: {
                    type: "string",
                    demandOption: false,
                    default: "30000000",
                    describe: "issuedTokens value of liquidation vault"
                },
                toBeRedeemed: {
                    type: "string",
                    demandOption: false,
                    default: "10000000",
                    describe: "toBeRedeemedTokens value of liquidation vault"
                },
                collateral: {
                    type: "string",
                    demandOption: false,
                    default: "100000000",
                    describe: "collateral value of liquidation vault"
                }
            }, setLiquidationVault(sudoAccountInterBtcApi))
                .command("vaultIssuedTokens", "Sets issued tokens of a vault", Object.assign(Object.assign({}, SET_VAULT_PARAMS_BASE), { value: {
                    alias: "v",
                    type: "string",
                    demandOption: true,
                    describe: "new issued tokens value"
                } }), setVaultIssuedTokens(sudoAccountInterBtcApi))
                .command("vaultPremiumRedeem", "Sets collateral ratio of vault to be within premium redeem range", SET_VAULT_PARAMS_BASE, setPremiumRedeem(sudoAccountInterBtcApi))
                .command("vaultBan", "Bans vault for next 1000 blocks", SET_VAULT_PARAMS_BASE, setVaultBan(sudoAccountInterBtcApi))
                .command("vaultUnban", "Unbans vault", SET_VAULT_PARAMS_BASE, setVaultUnban(sudoAccountInterBtcApi))
                .command("vaultFund", "Funds vault account with collateral token", {
                accountId: {
                    alias: "a",
                    type: "string",
                    demandOption: false,
                    describe: "accountId of the vault",
                    default: defaultVaultAccountId
                },
                collateralSymbol: {
                    alias: "c",
                    type: "string",
                    demandOption: false,
                    describe: "collateral currency symbol of the vault",
                    default: defaultCollateralSymbol
                }
            }, fundVaultAccount(sudoAccountInterBtcApi))
                .command("vaultReward", "Sets claimable amount of rewards for vault", SET_VAULT_PARAMS_BASE, setVaultReward(sudoAccountInterBtcApi))
                .help()
                .strict()
                .recommendCommands()
                .argv;
        }
        catch (error) {
            console.error(`Error: ${error.message}`);
        }
    });
}
main();
//# sourceMappingURL=set-state.js.map