"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());
    });
};
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 Environment_1 = require("../../../utils/environment/Environment");
const getContract_1 = require("../../../utils/solidity/getContract");
const deployContract_1 = require("../../../utils/solidity/deployContract");
const Contracts_1 = require("../../../Contracts");
/* eslint no-bitwise: ["error", { "allow": ["&"] }] */
function bytesToHex(byteArray) {
    const strNum = Array.from(byteArray, (byte) => `0${(byte & 0xff).toString(16)}`.slice(-2)).join('');
    const num = `0x${strNum}`;
    return num;
}
exports.deployKyberEnvironment = (environment, tokens) => __awaiter(this, void 0, void 0, function* () {
    const debug = environment.logger('melon:protocol:exchanges:deploy-kyber', Environment_1.LogLevels.DEBUG);
    const deployer = environment.wallet.address.toString();
    // const address = await deployContract(
    //   'KyberNetwork.sol',
    //   [],
    //   environment,
    // );
    // return address;
    // const opts = {
    //   from: deployer,
    //   gas: 8000000,
    //   gasPrice: 10,
    // };
    const [mlnToken, eurToken] = tokens;
    const minimalRecordResolution = 2;
    const maxPerBlockImbalance = new bignumber_js_1.default(Math.pow(10, 29)).toFixed();
    const validRateDurationInBlocks = 500;
    const precisionUnits = new bignumber_js_1.default(10).pow(18).toFixed();
    const maxTotalImbalance = new bignumber_js_1.default(maxPerBlockImbalance)
        .mul(12)
        .toFixed();
    // base buy and sell rates (prices)
    const baseBuyRate1 = [];
    const baseSellRate1 = [];
    // compact data.
    const sells = [bytesToHex(0)];
    const buys = [bytesToHex(0)];
    const indices = [0];
    const conversionRates = getContract_1.getContract(environment, Contracts_1.Contracts.ConversionRates, yield deployContract_1.deployContract(environment, Contracts_1.Contracts.ConversionRates, [deployer]));
    const kgtTokenAddress = yield deployContract_1.deployContract(environment, 'TestToken', [
        'KGT',
        'KGT',
        18,
    ]);
    const kyberNetworkContract = getContract_1.getContract(environment, Contracts_1.Contracts.KyberNetwork, yield deployContract_1.deployContract(environment, Contracts_1.Contracts.KyberNetwork, [deployer]));
    yield conversionRates.methods
        .setValidRateDurationInBlocks(validRateDurationInBlocks)
        .send({ from: deployer, gas: 8000000 });
    yield conversionRates.methods
        .addToken(mlnToken.address)
        .send({ from: deployer, gas: 8000000 });
    yield conversionRates.methods
        .setTokenControlInfo(mlnToken.address, minimalRecordResolution, maxPerBlockImbalance, maxTotalImbalance)
        .send({ from: deployer, gas: 8000000 });
    yield conversionRates.methods
        .enableTokenTrade(mlnToken.address)
        .send({ from: deployer, gas: 8000000 });
    const kyberReserveContract = getContract_1.getContract(environment, Contracts_1.Contracts.KyberReserve, yield deployContract_1.deployContract(environment, Contracts_1.Contracts.KyberReserve, [
        kyberNetworkContract.options.address,
        conversionRates.options.address,
        deployer,
    ]));
    yield conversionRates.methods
        .setReserveAddress(kyberReserveContract.options.address)
        .send({ from: deployer, gas: 8000000 });
    yield kyberNetworkContract.methods
        .addReserve(kyberReserveContract.options.address, true)
        .send({ from: deployer, gas: 8000000 });
    yield kyberReserveContract.methods
        .approveWithdrawAddress(mlnToken.address, deployer, true)
        .send({ from: deployer, gas: 8000000 });
    yield kyberReserveContract.methods
        .enableTrade()
        .send({ from: deployer, gas: 8000000 });
    const mlnTokenContract = getContract_1.getContract(environment, Contracts_1.Contracts.PreminedToken, mlnToken.address);
    // Set pricing for Token
    yield mlnTokenContract.methods
        .transfer(kyberReserveContract.options.address, new bignumber_js_1.default(Math.pow(10, 23)).toFixed())
        .send({ from: deployer, gas: 8000000 });
    const mlnPrice = new bignumber_js_1.default(Math.pow(10, 18)); // Arbritrary for now
    const ethersPerToken = mlnPrice.toFixed();
    const tokensPerEther = new bignumber_js_1.default(precisionUnits)
        .mul(precisionUnits)
        .div(ethersPerToken)
        .toFixed(0);
    baseBuyRate1.push(tokensPerEther);
    baseSellRate1.push(ethersPerToken);
    const currentBlock = yield environment.eth.getBlockNumber();
    yield conversionRates.methods
        .addOperator(deployer)
        .send({ from: deployer, gas: 8000000 });
    debug('setBaseRate', [
        [mlnToken.address],
        baseBuyRate1,
        baseSellRate1,
        buys,
        sells,
        currentBlock,
        indices,
    ]);
    yield conversionRates.methods
        .setBaseRate([mlnToken.address], baseBuyRate1, baseSellRate1, buys, sells, currentBlock, indices)
        .send({ from: deployer, gas: 8000000 });
    yield conversionRates.methods
        .setQtyStepFunction(mlnToken.address, [0], [0], [0], [0])
        .send({ from: deployer, gas: 8000000 });
    yield conversionRates.methods
        .setImbalanceStepFunction(mlnToken.address, [0], [0], [0], [0])
        .send({ from: deployer, gas: 8000000 });
    const kyberWhiteListContract = getContract_1.getContract(environment, Contracts_1.Contracts.KyberWhiteList, yield deployContract_1.deployContract(environment, Contracts_1.Contracts.KyberWhiteList, [
        deployer,
        kgtTokenAddress.toString(),
    ]));
    yield kyberWhiteListContract.methods
        .addOperator(deployer)
        .send({ from: deployer, gas: 8000000 });
    yield kyberWhiteListContract.methods
        .setCategoryCap(0, new bignumber_js_1.default(Math.pow(10, 28)).toFixed())
        .send({ from: deployer, gas: 8000000 });
    yield kyberWhiteListContract.methods
        .setSgdToEthRate(30000)
        .send({ from: deployer, gas: 8000000 });
    const feeBurnerAddress = yield deployContract_1.deployContract(environment, 'FeeBurner', [
        deployer,
        mlnToken.address,
        kyberNetworkContract.options.address,
    ]);
    const expectedRateAddress = yield deployContract_1.deployContract(environment, 'ExpectedRate', [kyberNetworkContract.options.address, deployer]);
    yield environment.eth.sendTransaction({
        from: deployer,
        to: kyberReserveContract.options.address,
        value: new bignumber_js_1.default(Math.pow(10, 22)),
    });
    yield kyberReserveContract.methods
        .setContracts(kyberNetworkContract.options.address, conversionRates.options.address, '0x0000000000000000000000000000000000000000')
        .send({ from: deployer, gas: 8000000 });
    const kyberNetworkProxyContract = getContract_1.getContract(environment, Contracts_1.Contracts.KyberNetworkProxy, yield deployContract_1.deployContract(environment, Contracts_1.Contracts.KyberNetworkProxy, [deployer]));
    yield kyberNetworkProxyContract.methods
        .setKyberNetworkContract(kyberNetworkContract.options.address)
        .send({ from: deployer, gas: 8000000 });
    yield kyberNetworkContract.methods
        .setWhiteList(kyberWhiteListContract.options.address)
        .send({ from: deployer, gas: 8000000 });
    yield kyberNetworkContract.methods
        .setExpectedRate(expectedRateAddress.toString())
        .send({ from: deployer, gas: 8000000 });
    yield kyberNetworkContract.methods
        .setFeeBurner(feeBurnerAddress.toString())
        .send({ from: deployer, gas: 8000000 });
    yield kyberNetworkContract.methods
        .setKyberProxy(kyberNetworkProxyContract.options.address)
        .send({ from: deployer, gas: 8000000 });
    yield kyberNetworkContract.methods
        .setEnable(true)
        .send({ from: deployer, gas: 8000000 });
    yield kyberNetworkContract.methods
        .listPairForReserve(kyberReserveContract.options.address, mlnToken.address.toString(), true, true, true)
        .send({ from: deployer, gas: 8000000 });
    // // Add Eur Token
    const eurTokenContract = getContract_1.getContract(environment, Contracts_1.Contracts.PreminedToken, eurToken.address);
    yield conversionRates.methods
        .addToken(eurToken.address)
        .send({ from: deployer, gas: 8000000 });
    yield conversionRates.methods
        .setTokenControlInfo(eurToken.address, minimalRecordResolution, maxPerBlockImbalance, maxTotalImbalance)
        .send({ from: deployer, gas: 8000000 });
    yield conversionRates.methods
        .enableTokenTrade(eurToken.address)
        .send({ from: deployer, gas: 8000000 });
    yield kyberReserveContract.methods
        .approveWithdrawAddress(eurToken.address, deployer, true)
        .send({ from: deployer, gas: 8000000 });
    yield eurTokenContract.methods
        .transfer(kyberReserveContract.options.address, new bignumber_js_1.default(Math.pow(10, 23)).toFixed())
        .send({ from: deployer, gas: 8000000 });
    const eurPrice = new bignumber_js_1.default(Math.pow(10, 18)); // Arbritrary for now
    const ethersPerEurToken = eurPrice.toFixed();
    const eurTokensPerEther = new bignumber_js_1.default(precisionUnits)
        .mul(precisionUnits)
        .div(ethersPerEurToken)
        .toFixed(0);
    yield conversionRates.methods
        .setBaseRate([eurToken.address], [eurTokensPerEther], [ethersPerEurToken], buys, sells, currentBlock, indices)
        .send({ from: deployer, gas: 8000000 });
    yield conversionRates.methods
        .setQtyStepFunction(eurToken.address, [0], [0], [0], [0])
        .send({ from: deployer, gas: 8000000 });
    yield conversionRates.methods
        .setImbalanceStepFunction(eurToken.address, [0], [0], [0], [0])
        .send({ from: deployer, gas: 8000000 });
    yield kyberNetworkContract.methods
        .listPairForReserve(kyberReserveContract.options.address, eurToken.address, true, true, true)
        .send({ from: deployer, gas: 8000000 });
    // TODO
    // await governanceAction(
    //   { from: deployer },
    //   Governance,
    //   canonicalPriceFeed,
    //   "registerExchange",
    //   [
    //     KyberNetworkProxy.options.address,
    //     KyberAdapter.options.address,
    //     true,
    //     [takeOrderSignature],
    //   ],
    // );
    return {
        conversionRates: conversionRates.options.address,
        kyberNetwork: kyberNetworkContract.options.address,
        kyberNetworkProxy: kyberNetworkProxyContract.options.address,
    };
});
