"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 hardhat_1 = require("hardhat");
const deploymentConfig_1 = require("../helpers/deploymentConfig");
const configurePriceFeeds = (hre) => __awaiter(void 0, void 0, void 0, function* () {
    const networkName = hre.network.name;
    const resilientOracle = yield hre.ethers.getContract("ResilientOracle");
    const binanceOracle = yield hre.ethers.getContractOrNull("BinanceOracle");
    const chainlinkOracle = yield hre.ethers.getContractOrNull("ChainlinkOracle");
    const oraclesData = yield (0, deploymentConfig_1.getOraclesData)();
    const commands = [];
    for (const asset of deploymentConfig_1.assets[networkName]) {
        const { oracle } = asset;
        console.log(`Adding commands for configuring ${asset.token}`);
        console.log(`Adding a command to configure ${oracle} oracle for ${asset.token}`);
        const { getTokenConfig, getDirectPriceConfig } = oraclesData[oracle];
        if (oraclesData[oracle].underlyingOracle.address === (chainlinkOracle === null || chainlinkOracle === void 0 ? void 0 : chainlinkOracle.address) &&
            getDirectPriceConfig !== undefined) {
            const assetConfig = getDirectPriceConfig(asset);
            commands.push({
                contract: oraclesData[oracle].underlyingOracle.address,
                signature: "setDirectPrice(address,uint256)",
                value: 0,
                parameters: [assetConfig.asset, assetConfig.price],
            });
        }
        if (oraclesData[oracle].underlyingOracle.address !== (binanceOracle === null || binanceOracle === void 0 ? void 0 : binanceOracle.address) && getTokenConfig !== undefined) {
            const tokenConfig = getTokenConfig(asset, networkName);
            commands.push({
                contract: oraclesData[oracle].underlyingOracle.address,
                signature: "setTokenConfig((address,address,uint256))",
                value: 0,
                parameters: [[tokenConfig.asset, tokenConfig.feed, tokenConfig.maxStalePeriod]],
            });
        }
        const { getStalePeriodConfig } = oraclesData[oracle];
        if (oraclesData[oracle].underlyingOracle.address === (binanceOracle === null || binanceOracle === void 0 ? void 0 : binanceOracle.address) && getStalePeriodConfig !== undefined) {
            const tokenConfig = getStalePeriodConfig(asset);
            commands.push({
                contract: oraclesData[oracle].underlyingOracle.address,
                signature: "setMaxStalePeriod(string,uint256)",
                value: 0,
                parameters: [tokenConfig],
            });
        }
        console.log(``);
        console.log(`Adding a command to configure resilient oracle for ${asset.token}`);
        commands.push({
            contract: resilientOracle.address,
            signature: "setTokenConfig((address,address[3],bool[3]))",
            value: 0,
            parameters: [[asset.address, oraclesData[oracle].oracles, oraclesData[oracle].enableFlagsForOracles]],
        });
    }
    return commands;
});
const acceptOwnership = (contractName, targetOwner, hre) => __awaiter(void 0, void 0, void 0, function* () {
    if (!hre.network.live) {
        return [];
    }
    const abi = ["function owner() view returns (address)"];
    let deployment;
    try {
        deployment = yield hre.deployments.get(contractName);
    }
    catch (error) {
        if (error.message.includes("No deployment found for")) {
            return [];
        }
        throw error;
    }
    const contract = yield hardhat_1.ethers.getContractAt(abi, deployment.address);
    if ((yield contract.owner()) === targetOwner) {
        return [];
    }
    console.log(`Adding a command to accept the admin rights over ${contractName}`);
    return [
        {
            contract: deployment.address,
            signature: "acceptOwnership()",
            parameters: [],
            value: 0,
        },
    ];
});
const makeRole = (mainnetBehavior, targetContract, method) => {
    if (mainnetBehavior && targetContract === hardhat_1.ethers.constants.AddressZero) {
        return hardhat_1.ethers.utils.keccak256(hardhat_1.ethers.utils.solidityPack(["bytes32", "string"], [hardhat_1.ethers.constants.HashZero, method]));
    }
    return hardhat_1.ethers.utils.keccak256(hardhat_1.ethers.utils.solidityPack(["address", "string"], [targetContract, method]));
};
const hasPermission = (accessControl, targetContract, method, caller, hre) => __awaiter(void 0, void 0, void 0, function* () {
    const role = makeRole(hre.network.name === "bscmainnet", targetContract, method);
    return accessControl.hasRole(role, caller);
});
const timelockOraclePermissions = (timelock) => {
    const methods = [
        "pause()",
        "unpause()",
        "setOracle(address,address,uint8)",
        "enableOracle(address,uint8,bool)",
        "setTokenConfig(TokenConfig)",
        "setDirectPrice(address,uint256)",
        "setValidateConfig(ValidateConfig)",
        "setMaxStalePeriod(string,uint256)",
        "setSymbolOverride(string,string)",
        "setUnderlyingPythOracle(address)",
    ];
    return methods.map(method => ({
        caller: timelock,
        target: deploymentConfig_1.ANY_CONTRACT,
        method,
    }));
};
const configureAccessControls = (hre) => __awaiter(void 0, void 0, void 0, function* () {
    const networkName = hre.network.name;
    const accessControlManagerAddress = deploymentConfig_1.ADDRESSES[networkName].acm;
    const accessControlConfig = timelockOraclePermissions(deploymentConfig_1.ADDRESSES[networkName].timelock);
    const accessControlManager = yield hardhat_1.ethers.getContractAt("AccessControlManager", accessControlManagerAddress);
    const commands = yield Promise.all(accessControlConfig.map((entry) => __awaiter(void 0, void 0, void 0, function* () {
        const { caller, target, method } = entry;
        if (yield hasPermission(accessControlManager, caller, method, target, hre)) {
            return [];
        }
        return [
            {
                contract: accessControlManagerAddress,
                signature: "giveCallPermission(address,string,address)",
                argTypes: ["address", "string", "address"],
                parameters: [target, method, caller],
                value: 0,
            },
        ];
    })));
    return commands.flat();
});
const func = function (hre) {
    return __awaiter(this, void 0, void 0, function* () {
        const owner = deploymentConfig_1.ADDRESSES[hre.network.name].timelock;
        console.log(`owner: ${owner}`);
        const commands = [
            ...(yield configureAccessControls(hre)),
            ...(yield acceptOwnership("ResilientOracle", owner, hre)),
            ...(yield acceptOwnership("ChainlinkOracle", owner, hre)),
            ...(yield acceptOwnership("RedStoneOracle", owner, hre)),
            ...(yield acceptOwnership("BoundValidator", owner, hre)),
            ...(yield acceptOwnership("BinanceOracle", owner, hre)),
            ...(yield configurePriceFeeds(hre)),
        ];
        if (hre.network.live) {
            console.log("Please propose a VIP with the following commands:");
            console.log(JSON.stringify(commands.map(c => ({ target: c.contract, signature: c.signature, params: c.parameters }))));
        }
        else {
            throw Error("This script is only used for live networks.");
        }
    });
};
func.tags = ["VIP"];
func.skip = (hre) => __awaiter(void 0, void 0, void 0, function* () { return hre.network.name === "hardhat"; });
exports.default = func;
//# sourceMappingURL=3-vip-based-configuration.js.map