"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const Contracts_1 = require("../../Contracts");
const getToken_1 = require("../../contracts/dependencies/token/calls/getToken");
const deploy_1 = require("../../contracts/dependencies/token/transactions/deploy");
const deployMatchingMarket_1 = require("../../contracts/exchanges/transactions/deployMatchingMarket");
const getContract_1 = require("../solidity/getContract");
const deployAndGetContract_1 = require("../solidity/deployAndGetContract");
const Environment_1 = require("../environment/Environment");
const token_math_1 = require("@melonproject/token-math");
/**
 * Deploys a fresh set of (potentially) mocked contracts.
 * Arguments can be overriden to deploy mock or real contracts as needed.
 */
exports.deployMockSystem = (env, { accountingContract = Contracts_1.Contracts.MockAccounting, engineContract = Contracts_1.Contracts.Engine, feeManagerContract = Contracts_1.Contracts.MockFeeManager, fees = [], hubContract = Contracts_1.Contracts.MockHub, policyManagerContract = Contracts_1.Contracts.PolicyManager, participationContract = Contracts_1.Contracts.Participation, priceSourceContract = Contracts_1.Contracts.TestingPriceFeed, registryContract = Contracts_1.Contracts.MockRegistry, sharesContract = Contracts_1.Contracts.MockShares, tradingContract = Contracts_1.Contracts.Trading, vaultContract = Contracts_1.Contracts.Vault, versionContract = Contracts_1.Contracts.MockVersion, rankingContract = Contracts_1.Contracts.FundRanking, } = {}) => __awaiter(this, void 0, void 0, function* () {
    const debug = env.logger('melon:protocol:utils', Environment_1.LogLevels.DEBUG);
    const accounts = yield env.eth.getAccounts();
    debug('Deploying mocks from', accounts[0]);
    const wethTokenAddress = yield deploy_1.deployWeth(env);
    const mlnTokenAddress = yield deploy_1.deployToken(env, 'MLN');
    const baseTokenAddress = mlnTokenAddress;
    const quoteTokenAddress = wethTokenAddress;
    const quoteToken = yield getToken_1.getToken(env, quoteTokenAddress);
    const baseToken = yield getToken_1.getToken(env, baseTokenAddress);
    const mln = yield getContract_1.getContract(env, Contracts_1.Contracts.StandardToken, mlnTokenAddress);
    const weth = yield getContract_1.getContract(env, Contracts_1.Contracts.Weth, wethTokenAddress);
    // Deposit Ether to get WETH Tokens
    const depositAmount = token_math_1.power(new token_math_1.BigInteger(10), new token_math_1.BigInteger(24));
    yield weth.methods
        .deposit()
        .send({ from: env.wallet.address, value: `${depositAmount}` });
    const priceSource = yield deployAndGetContract_1.deployAndGetContract(env, priceSourceContract, [
        quoteToken.address.toString(),
        quoteToken.decimals,
    ]);
    const matchingMarketAddress = yield deployMatchingMarket_1.deployMatchingMarket(env, {
        tokens: [quoteToken, baseToken],
    });
    const matchingMarketAdapter = yield deployAndGetContract_1.deployAndGetContract(env, Contracts_1.Contracts.MatchingMarketAdapter);
    const version = yield deployAndGetContract_1.deployAndGetContract(env, versionContract);
    const registry = yield deployAndGetContract_1.deployAndGetContract(env, registryContract);
    yield registry.methods
        .setPriceSource(priceSource.options.address.toString())
        .send({ from: accounts[0] });
    yield registry.methods
        .setMlnToken(`${mlnTokenAddress}`)
        .send({ from: accounts[0] });
    yield registry.methods
        .setNativeAsset(`${wethTokenAddress}`)
        .send({ from: accounts[0] });
    yield registry.methods
        .registerAdapterForExchange(matchingMarketAddress.toString(), matchingMarketAdapter.options.address.toString())
        .send({ from: accounts[0] });
    const ranking = yield deployAndGetContract_1.deployAndGetContract(env, rankingContract);
    const hub = yield deployAndGetContract_1.deployAndGetContract(env, hubContract);
    yield hub.methods
        .setManager(env.wallet.address.toString())
        .send({ from: env.wallet.address.toString() });
    yield hub.methods
        .setName('Mock')
        .send({ from: env.wallet.address.toString() });
    const accounting = yield deployAndGetContract_1.deployAndGetContract(env, accountingContract, [
        hub.options.address.toString(),
        quoteToken.address.toString(),
        wethTokenAddress.toString(),
        [quoteToken.address.toString(), baseToken.address.toString()],
    ]);
    const feeManager = yield deployAndGetContract_1.deployAndGetContract(env, feeManagerContract, [
        hub.options.address.toString(),
        quoteToken.address.toString(),
        fees.map(f => f.feeAddress.toString()),
        fees.map(f => f.feePeriod),
        fees.map(f => f.feeRate),
    ]);
    const policyManager = yield deployAndGetContract_1.deployAndGetContract(env, policyManagerContract, [
        hub.options.address.toString(),
    ]);
    const participation = yield deployAndGetContract_1.deployAndGetContract(env, participationContract, [
        hub.options.address.toString(),
        [quoteToken.address.toString(), baseToken.address.toString()],
        registry.options.address.toString(),
    ]);
    const shares = yield deployAndGetContract_1.deployAndGetContract(env, sharesContract, [
        hub.options.address.toString(),
    ]);
    const trading = yield deployAndGetContract_1.deployAndGetContract(env, tradingContract, [
        hub.options.address.toString(),
        [matchingMarketAddress.toString()],
        [matchingMarketAdapter.options.address.toString()],
        [true],
        registry.options.address.toString(),
    ]);
    const vault = yield deployAndGetContract_1.deployAndGetContract(env, vaultContract, [
        hub.options.address.toString(),
    ]);
    // TODO: replace with raw function when MockEngine is available
    const engine = yield deployAndGetContract_1.deployAndGetContract(env, engineContract, [
        30 * 24 * 60 * 60,
    ]);
    yield registry.methods
        .setEngine(engine.options.address.toString())
        .send({ from: accounts[0] });
    yield engine.methods
        .setRegistry(registry.options.address.toString())
        .send({ from: accounts[0], gas: 8000000 });
    yield hub.methods
        .setSpokes([
        accounting.options.address.toString(),
        feeManager.options.address.toString(),
        participation.options.address.toString(),
        policyManager.options.address.toString(),
        shares.options.address.toString(),
        trading.options.address.toString(),
        vault.options.address.toString(),
        priceSource.options.address.toString(),
        registry.options.address.toString(),
        version.options.address.toString(),
        engine.options.address.toString(),
        mlnTokenAddress.toString(),
    ])
        .send({ from: env.wallet.address.toString(), gas: 8000000 });
    const toInit = [
        accounting,
        participation,
        shares,
        trading,
        vault,
        feeManager,
    ];
    for (const contract of toInit) {
        yield hub.methods
            .initializeSpoke(contract.options.address.toString())
            .send({ from: env.wallet.address.toString(), gas: 8000000 });
    }
    yield hub.methods
        .setPermissions()
        .send({ from: env.wallet.address.toString(), gas: 8000000 });
    const contracts = {
        accounting,
        engine,
        feeManager,
        hub,
        mln,
        participation,
        policyManager,
        priceSource,
        ranking,
        registry,
        shares,
        trading,
        vault,
        version,
        weth,
    };
    return contracts;
});
