"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const IUniswapV2Router02_json_1 = __importDefault(require("@uniswap/v2-periphery/build/IUniswapV2Router02.json"));
const SwapRouter_json_1 = __importDefault(require("@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json"));
const networks_1 = require("@zetachain/networks");
const axios_1 = __importDefault(require("axios"));
const ethers_1 = require("ethers");
const config_1 = require("hardhat/config");
const lodash_1 = require("lodash");
const SystemContract_sol_1 = require("../types/factories/SystemContract.sol");
const addresses_mainnet_json_1 = __importDefault(require("./addresses.mainnet.json"));
const addresses_testnet_json_1 = __importDefault(require("./addresses.testnet.json"));
const api = {
    zeta_mainnet: {
        evm: "https://zetachain-evm.blockpi.network/v1/rpc/public",
        rpc: "https://zetachain.blockpi.network/lcd/v1/public",
    },
    zeta_testnet: {
        evm: "https://zetachain-athens-evm.blockpi.network/v1/rpc/public",
        rpc: "https://zetachain-athens.blockpi.network/lcd/v1/public",
    },
};
const fetchChains = async (network) => {
    const URL = `${api[network].rpc}/zeta-chain/observer/supportedChains`;
    try {
        const response = await axios_1.default.get(URL);
        if (response.status === 200) {
            return response.data.chains;
        }
        else {
            console.error("Error fetching chains:", response.status, response.statusText);
        }
    }
    catch (error) {
        console.error("Error fetching chains:", error);
    }
};
const fetchTssData = async (chains, addresses, network) => {
    const isMainnet = network == "zeta_mainnet";
    const bitcoinChainID = isMainnet ? "8332" : "18332";
    const URL = `${api[network].rpc}/zeta-chain/observer/get_tss_address/${bitcoinChainID}`;
    try {
        const tssResponse = await axios_1.default.get(URL);
        if (tssResponse.status === 200) {
            const { btc, eth } = tssResponse.data;
            addresses.push({
                address: btc,
                category: "omnichain",
                chain_id: bitcoinChainID,
                chain_name: isMainnet ? "btc_mainnet" : "btc_testnet",
                type: "tss",
            });
            addresses.push({
                address: eth,
                category: "omnichain",
                chain_id: isMainnet ? "1" : "11155111",
                chain_name: isMainnet ? "eth_mainnet" : "sepolia_testnet",
                type: "tss",
            });
        }
        else {
            console.error("Error fetching TSS data:", tssResponse.status, tssResponse.statusText);
        }
    }
    catch (error) {
        console.error("Error fetching TSS data:", error);
    }
};
const fetchSystemContract = async (addresses, network) => {
    const chain_id = network === "zeta_mainnet" ? 7000 : 7001;
    const URL = `${api[network].rpc}/zeta-chain/fungible/system_contract`;
    try {
        const systemContractResponse = await axios_1.default.get(URL);
        if (systemContractResponse.status === 200) {
            addresses.push({
                address: systemContractResponse.data.SystemContract.system_contract,
                category: "omnichain",
                chain_id,
                chain_name: network,
                type: "systemContract",
            });
            addresses.push({
                address: systemContractResponse.data.SystemContract.connector_zevm,
                category: "messaging",
                chain_id,
                chain_name: network,
                type: "connector",
            });
        }
        else {
            console.error("Error fetching system contract:", systemContractResponse.statusText);
        }
    }
    catch (error) {
        console.error("Error fetching system contract:", error);
    }
};
const fetchForeignCoinsData = async (chains, addresses, network) => {
    const chain_id = network === "zeta_mainnet" ? 7000 : 7001;
    const URL = `${api[network].rpc}/zeta-chain/fungible/foreign_coins`;
    try {
        const foreignCoinsResponse = await axios_1.default.get(URL);
        if (foreignCoinsResponse.status === 200) {
            foreignCoinsResponse.data.foreignCoins.forEach((token) => {
                addresses.push({
                    address: token.zrc20_contract_address,
                    asset: token.asset,
                    category: "omnichain",
                    chain_id,
                    chain_name: network,
                    coin_type: token.coin_type.toLowerCase(),
                    decimals: token.decimals,
                    description: token.name,
                    foreign_chain_id: token.foreign_chain_id,
                    symbol: token.symbol,
                    type: "zrc20",
                });
            });
        }
        else {
            console.error("Error fetching foreign coins data:", foreignCoinsResponse.status, foreignCoinsResponse.statusText);
        }
    }
    catch (error) {
        console.error("Error fetching foreign coins data:", error);
    }
};
const fetchAthensAddresses = async (addresses, network) => {
    const chain_id = network === "zeta_mainnet" ? 7000 : 7001;
    const systemContract = addresses.find((a) => {
        return a.chain_name === network && a.type === "systemContract";
    })?.address;
    const provider = new ethers_1.ethers.JsonRpcProvider(api[network].evm);
    const sc = SystemContract_sol_1.SystemContract__factory.connect(systemContract, provider);
    const common = {
        category: "omnichain",
        chain_id,
        chain_name: network,
    };
    try {
        addresses.push({ ...common, address: await sc.uniswapv2FactoryAddress(), type: "uniswapV2Factory" });
        addresses.push({ ...common, address: await sc.wZetaContractAddress(), type: "zetaToken" });
        addresses.push({ ...common, address: await sc.uniswapv2Router02Address(), type: "uniswapV2Router02" });
        // addresses.push({ ...common, address: await sc.zetaConnectorZEVMAddress(), type: "zetaConnectorZEVM" });
        addresses.push({ ...common, address: await sc.FUNGIBLE_MODULE_ADDRESS(), type: "fungibleModule" });
    }
    catch (error) {
        console.error("Error fetching addresses from ZetaChain:", error);
    }
};
const fetchChainSpecificAddresses = async (chains, addresses, network) => {
    await Promise.all(chains.map(async (chain) => {
        return axios_1.default
            .get(`${api[network].rpc}/zeta-chain/observer/get_chain_params_for_chain/${chain.chain_id}`)
            .then(({ data }) => {
            const zetaToken = data.chain_params.zeta_token_contract_address;
            if (zetaToken && zetaToken != ethers_1.ethers.ZeroAddress) {
                addresses.push({
                    address: zetaToken,
                    category: "messaging",
                    chain_id: parseInt(chain.chain_id),
                    chain_name: chain.name,
                    type: "zetaToken",
                });
            }
            const connector = data.chain_params.connector_contract_address;
            if (connector && connector != ethers_1.ethers.ZeroAddress) {
                addresses.push({
                    address: connector,
                    category: "messaging",
                    chain_id: parseInt(chain.chain_id),
                    chain_name: chain.name,
                    type: "connector",
                });
            }
            const erc20Custody = data.chain_params.erc20_custody_contract_address;
            if (erc20Custody && erc20Custody != ethers_1.ethers.ZeroAddress) {
                addresses.push({
                    address: erc20Custody,
                    category: "omnichain",
                    chain_id: parseInt(chain.chain_id),
                    chain_name: chain.name,
                    type: "erc20Custody",
                });
            }
            const gateway = data.chain_params.gateway_address;
            if (gateway && gateway != ethers_1.ethers.ZeroAddress) {
                addresses.push({
                    address: gateway,
                    category: "omnichain",
                    chain_id: parseInt(chain.chain_id),
                    chain_name: chain.name,
                    type: "gateway",
                });
            }
        });
    }));
};
const fetchFactoryV2 = async (addresses, network) => {
    const routers = addresses.filter((a) => a.type === "uniswapV2Router02");
    for (const router of routers) {
        const rpc = (0, networks_1.getEndpoints)("evm", router.chain_name)[0]?.url;
        const provider = new ethers_1.ethers.JsonRpcProvider(rpc);
        const routerContract = new ethers_1.ethers.Contract(router.address, IUniswapV2Router02_json_1.default.abi, provider);
        try {
            const wethAddress = await routerContract.WETH();
            const factoryAddress = await routerContract.factory();
            // Skip ZetaChain as we've already added ZETA token
            if (router.chain_id !== 7000 && router.chain_id !== 7001) {
                addresses.push({
                    address: wethAddress,
                    category: "messaging",
                    chain_id: router.chain_id,
                    chain_name: router.chain_name,
                    type: "weth9",
                });
                addresses.push({
                    address: factoryAddress,
                    category: "messaging",
                    chain_id: router.chain_id,
                    chain_name: router.chain_name,
                    type: "uniswapV2Factory",
                });
            }
        }
        catch (error) {
            console.error(`Error fetching factory and WETH for router v2 ${router.address}:`, error);
        }
    }
};
const fetchFactoryV3 = async (addresses, network) => {
    const routers = addresses.filter((a) => a.type === "uniswapV3Router");
    for (const router of routers) {
        const rpc = (0, networks_1.getEndpoints)("evm", router.chain_name)[0]?.url;
        const provider = new ethers_1.ethers.JsonRpcProvider(rpc);
        const routerContract = new ethers_1.ethers.Contract(router.address, SwapRouter_json_1.default.abi, provider);
        try {
            const wethAddress = await routerContract.WETH9();
            const factoryAddress = await routerContract.factory();
            if (router.chain_id !== 7000 && router.chain_id !== 7001) {
                const wethObj = {
                    address: wethAddress,
                    category: "messaging",
                    chain_id: router.chain_id,
                    chain_name: router.chain_name,
                    type: "weth9",
                };
                if (!addresses.some((e) => (0, lodash_1.isEqual)(e, wethObj))) {
                    addresses.push(wethObj);
                }
            }
            addresses.push({
                address: factoryAddress,
                category: "messaging",
                chain_id: router.chain_id,
                chain_name: router.chain_name,
                type: "uniswapV3Factory",
            });
        }
        catch (error) {
            console.error(`Error fetching factory for router v3 ${router.address}:`, error);
        }
    }
};
const main = async (args, hre) => {
    let addresses = [];
    const n = hre.network.name;
    if (n === "zeta_testnet") {
        addresses.push(...addresses_testnet_json_1.default);
    }
    else if (n === "zeta_mainnet") {
        addresses.push(...addresses_mainnet_json_1.default);
    }
    else {
        throw new Error(`Unsupported network: ${n}. Must be 'zeta_testnet' or 'zeta_mainnet'.`);
    }
    const network = n;
    const chains = await fetchChains(network);
    await fetchTssData(chains, addresses, network);
    await fetchSystemContract(addresses, network);
    await fetchForeignCoinsData(chains, addresses, network);
    await fetchAthensAddresses(addresses, network);
    await fetchChainSpecificAddresses(chains, addresses, network);
    await fetchFactoryV2(addresses, network);
    await fetchFactoryV3(addresses, network);
    addresses = addresses.sort((a, b) => {
        if (a.chain_id !== b.chain_id) {
            return a.chain_id - b.chain_id;
        }
        else if (a.type !== b.type) {
            return a.type.localeCompare(b.type);
        }
        else {
            return a.address.localeCompare(b.address);
        }
    });
    console.log(JSON.stringify(addresses, null, 2));
};
(0, config_1.task)("addresses", "").setAction(main);
