"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hubPoolFixture = void 0;
exports.setupHubPool = setupHubPool;
exports.deployHubPool = deployHubPool;
exports.enableTokensForLP = enableTokensForLP;
const tslib_1 = require("tslib");
require("@nomiclabs/hardhat-ethers");
require("@openzeppelin/hardhat-upgrades");
const hardhat_1 = tslib_1.__importDefault(require("hardhat"));
const getContractFactory_1 = require("../utils/getContractFactory");
const constants_1 = require("../constants");
const utils_1 = require("../utils");
const clients = tslib_1.__importStar(require("../../src/clients"));
const mocks_1 = require("../mocks");
const UmaEcosystemFixture_1 = require("./UmaEcosystemFixture");
const utils_2 = require("./utils");
async function setupHubPool(ethers, maxRefundPerRelayerRefundLeaf, maxL1TokensPerPoolRebalanceLeaf, destinationChainId = constants_1.destinationChainId, originChainId = constants_1.originChainId, lookbackForAllChains) {
    const [owner, depositor, relayer, dataworker] = await ethers.getSigners();
    const hubPoolChainId = await owner.getChainId();
    const { spokePool: spokePool_1, erc20: erc20_1 } = await (0, utils_1.deploySpokePoolWithToken)(originChainId);
    const { spokePool: spokePool_2, erc20: erc20_2 } = await (0, utils_1.deploySpokePoolWithToken)(destinationChainId);
    const { spokePool: spokePool_3 } = await (0, utils_1.deploySpokePoolWithToken)(constants_1.repaymentChainId);
    const { spokePool: spokePool_4 } = await (0, utils_1.deploySpokePoolWithToken)(hubPoolChainId);
    const spokePoolDeploymentBlocks = {
        [originChainId]: await spokePool_1.provider.getBlockNumber(),
        [destinationChainId]: await spokePool_2.provider.getBlockNumber(),
        [constants_1.repaymentChainId]: await spokePool_3.provider.getBlockNumber(),
        [hubPoolChainId]: await spokePool_4.provider.getBlockNumber(),
    };
    const testChainIdList = Object.keys(spokePoolDeploymentBlocks).map((_chainId) => Number(_chainId));
    const umaEcosystem = await (0, UmaEcosystemFixture_1.setupUmaEcosystem)(owner);
    const { hubPool, hubPoolDeploymentBlock, l1Token_1, l1Token_2 } = await (0, utils_1.deployAndConfigureHubPool)(owner, [
        { l2ChainId: destinationChainId, spokePool: spokePool_2 },
        { l2ChainId: originChainId, spokePool: spokePool_1 },
        { l2ChainId: constants_1.repaymentChainId, spokePool: spokePool_3 },
        { l2ChainId: hubPoolChainId, spokePool: spokePool_4 },
    ], umaEcosystem.finder.address, umaEcosystem.timer.address);
    await (0, utils_1.enableRoutesOnHubPool)(hubPool, [
        { destinationChainId: originChainId, l1Token: l1Token_1, destinationToken: erc20_1 },
        { destinationChainId: destinationChainId, l1Token: l1Token_1, destinationToken: erc20_2 },
        { destinationChainId: originChainId, l1Token: l1Token_2, destinationToken: erc20_2 },
        { destinationChainId: destinationChainId, l1Token: l1Token_2, destinationToken: erc20_1 },
        {
            destinationChainId: hubPoolChainId,
            l1Token: l1Token_1,
            destinationToken: l1Token_1,
        },
        { destinationChainId: constants_1.repaymentChainId, l1Token: l1Token_1, destinationToken: l1Token_1 },
    ]);
    await umaEcosystem.collateralWhitelist.addToWhitelist(l1Token_1.address);
    await umaEcosystem.store.setFinalFee(l1Token_1.address, { rawValue: "0" });
    await hubPool.setBond(l1Token_1.address, "1");
    await (0, utils_1.setupTokensForWallet)(hubPool, dataworker, [l1Token_1], undefined, 100);
    const { spyLogger, spy } = (0, utils_1.createSpyLogger)();
    const { configStore } = await (0, utils_1.deployConfigStore)(owner, [l1Token_1, l1Token_2], maxL1TokensPerPoolRebalanceLeaf, maxRefundPerRelayerRefundLeaf);
    const configStoreClient = new mocks_1.MockConfigStoreClient(spyLogger, configStore);
    configStoreClient.setAvailableChains(testChainIdList);
    await configStoreClient.update();
    const hubPoolClient = new clients.HubPoolClient(spyLogger, hubPool, configStoreClient, hubPoolDeploymentBlock, hubPoolChainId);
    const [spokePoolClient_1, spokePoolClient_2, spokePoolClient_3, spokePoolClient_4] = await _constructSpokePoolClientsWithLookback([spokePool_1, spokePool_2, spokePool_3, spokePool_4], [originChainId, destinationChainId, constants_1.repaymentChainId, hubPoolChainId], spyLogger, relayer, hubPoolClient, lookbackForAllChains, spokePoolDeploymentBlocks);
    const spokePoolClients = {
        [originChainId]: spokePoolClient_1,
        [destinationChainId]: spokePoolClient_2,
        [constants_1.repaymentChainId]: spokePoolClient_3,
        [hubPoolChainId]: spokePoolClient_4,
    };
    await (0, utils_1.setupTokensForWallet)(spokePool_1, owner, [l1Token_1, l1Token_2], undefined, 100);
    await l1Token_1.approve(hubPool.address, constants_1.amountToLp);
    await l1Token_2.approve(hubPool.address, constants_1.amountToLp);
    await hubPool.addLiquidity(l1Token_1.address, constants_1.amountToLp);
    await hubPool.addLiquidity(l1Token_2.address, constants_1.amountToLp);
    await (0, utils_1.setupTokensForWallet)(spokePool_1, depositor, [erc20_1, erc20_2], undefined, 10);
    await (0, utils_1.setupTokensForWallet)(spokePool_2, depositor, [erc20_2, erc20_1], undefined, 10);
    await (0, utils_1.setupTokensForWallet)(spokePool_1, relayer, [erc20_1, erc20_2, l1Token_1, l1Token_2], undefined, 10);
    await (0, utils_1.setupTokensForWallet)(spokePool_2, relayer, [erc20_1, erc20_2, l1Token_1, l1Token_2], undefined, 10);
    await spokePool_1.setCurrentTime(await (0, utils_1.getLastBlockTime)(spokePool_1.provider));
    await spokePool_2.setCurrentTime(await (0, utils_1.getLastBlockTime)(spokePool_2.provider));
    return {
        hubPool,
        spokePool_1,
        erc20_1,
        spokePool_2,
        erc20_2,
        l1Token_1,
        l1Token_2,
        configStore,
        timer: umaEcosystem.timer,
        spokePoolClient_1,
        spokePoolClient_2,
        spokePoolClient_3,
        spokePoolClient_4,
        spokePoolClients,
        configStoreClient: configStoreClient,
        mockedConfigStoreClient: configStoreClient,
        hubPoolClient,
        spyLogger,
        spy,
        owner,
        depositor,
        relayer,
        dataworker,
        updateAllClients: async () => {
            await configStoreClient.update();
            await hubPoolClient.update();
            await spokePoolClient_1.update();
            await spokePoolClient_2.update();
            await spokePoolClient_3.update();
            await spokePoolClient_4.update();
        },
    };
}
async function _constructSpokePoolClientsWithLookback(spokePools, spokePoolChains, spyLogger, signer, hubPoolClient, lookbackForAllChains, deploymentBlocks) {
    await hubPoolClient.update();
    const latestBlocks = await Promise.all(spokePools.map((x) => x.provider.getBlockNumber()));
    return spokePools.map((pool, i) => {
        return new clients.EVMSpokePoolClient(spyLogger, pool.connect(signer), hubPoolClient, spokePoolChains[i], deploymentBlocks?.[spokePoolChains[i]] ?? 0, lookbackForAllChains === undefined ? undefined : { from: latestBlocks[i] - lookbackForAllChains });
    });
}
async function deployHubPool(ethers, spokePoolName = "MockSpokePool") {
    const [signer, crossChainAdmin] = await ethers.getSigners();
    const parentFixture = await (0, UmaEcosystemFixture_1.setupUmaEcosystem)(signer);
    const weth = await (await (0, getContractFactory_1.getContractFactory)("WETH9", signer)).deploy();
    const usdc = await (await (0, getContractFactory_1.getContractFactory)("ExpandedERC20", signer)).deploy("USD Coin", "USDC", 6);
    await usdc.addMember(constants_1.TokenRolesEnum.MINTER, signer.address);
    const dai = await (await (0, getContractFactory_1.getContractFactory)("ExpandedERC20", signer)).deploy("DAI Stablecoin", "DAI", 18);
    await dai.addMember(constants_1.TokenRolesEnum.MINTER, signer.address);
    const usdt = await (await (0, getContractFactory_1.getContractFactory)("ExpandedERC20", signer)).deploy("USDT Stablecoin", "USDT", 6);
    await usdt.addMember(constants_1.TokenRolesEnum.MINTER, signer.address);
    const tokens = { weth, usdc, dai, usdt };
    await parentFixture.collateralWhitelist.addToWhitelist(weth.address);
    await parentFixture.collateralWhitelist.addToWhitelist(usdc.address);
    await parentFixture.collateralWhitelist.addToWhitelist(dai.address);
    await parentFixture.collateralWhitelist.addToWhitelist(usdt.address);
    await parentFixture.store.setFinalFee(weth.address, { rawValue: constants_1.finalFee });
    await parentFixture.store.setFinalFee(usdc.address, { rawValue: constants_1.finalFeeUsdc });
    await parentFixture.store.setFinalFee(dai.address, { rawValue: constants_1.finalFee });
    await parentFixture.store.setFinalFee(usdt.address, { rawValue: constants_1.finalFeeUsdt });
    const lpTokenFactory = await (await (0, getContractFactory_1.getContractFactory)("LpTokenFactory", signer)).deploy();
    const hubPool = await (await (0, getContractFactory_1.getContractFactory)("HubPool", signer)).deploy(lpTokenFactory.address, parentFixture.finder.address, weth.address, parentFixture.timer.address);
    await hubPool.setBond(weth.address, constants_1.bondAmount);
    await hubPool.setLiveness(7200);
    const mockAdapter = await (await (0, getContractFactory_1.getContractFactory)("Mock_Adapter", signer)).deploy();
    const mockSpoke = await hardhat_1.default.upgrades.deployProxy(await (0, getContractFactory_1.getContractFactory)(spokePoolName, signer), [0, crossChainAdmin.address, hubPool.address], { kind: "uups", unsafeAllow: ["delegatecall"], constructorArgs: [weth.address] });
    await hubPool.setCrossChainContracts(constants_1.repaymentChainId, mockAdapter.address, mockSpoke.address);
    await hubPool.setCrossChainContracts(constants_1.originChainId, mockAdapter.address, mockSpoke.address);
    const mainnetChainId = await signer.getChainId();
    const mockAdapterMainnet = await (await (0, getContractFactory_1.getContractFactory)("Mock_Adapter", signer)).deploy();
    const mockSpokeMainnet = await hardhat_1.default.upgrades.deployProxy(await (0, getContractFactory_1.getContractFactory)(spokePoolName, signer), [0, crossChainAdmin.address, hubPool.address], { kind: "uups", unsafeAllow: ["delegatecall"], constructorArgs: [weth.address] });
    await hubPool.setCrossChainContracts(mainnetChainId, mockAdapterMainnet.address, mockSpokeMainnet.address);
    const l2UsdtContract = await (await (0, getContractFactory_1.getContractFactory)("ExpandedERC20", signer)).deploy("USDT Stablecoin", "USDT", 6);
    await l2UsdtContract.addMember(constants_1.TokenRolesEnum.MINTER, signer.address);
    const mockTokens = {
        l2Weth: (0, constants_1.randomAddress)(),
        l2Dai: (0, constants_1.randomAddress)(),
        l2Usdc: (0, constants_1.randomAddress)(),
        l2Usdt: l2UsdtContract.address,
    };
    await hubPool.setPoolRebalanceRoute(constants_1.repaymentChainId, weth.address, mockTokens.l2Weth);
    await hubPool.setPoolRebalanceRoute(constants_1.repaymentChainId, dai.address, mockTokens.l2Dai);
    await hubPool.setPoolRebalanceRoute(constants_1.repaymentChainId, usdc.address, mockTokens.l2Usdc);
    await hubPool.setPoolRebalanceRoute(constants_1.repaymentChainId, usdt.address, mockTokens.l2Usdt);
    return {
        ...tokens,
        l2UsdtContract,
        ...mockTokens,
        hubPool,
        mockAdapter,
        mockSpoke,
        crossChainAdmin,
        ...parentFixture,
    };
}
exports.hubPoolFixture = (0, utils_2.createFixture)(async () => {
    return await deployHubPool(hardhat_1.default.ethers);
});
async function enableTokensForLP(owner, hubPool, _weth, tokens) {
    const lpTokens = [];
    for (const token of tokens) {
        await hubPool.enableL1TokenForLiquidityProvision(token.address);
        const pooledTokens = await hubPool.callStatic.pooledTokens(token.address);
        lpTokens.push(await (await (0, getContractFactory_1.getContractFactory)("ExpandedERC20", owner)).attach(pooledTokens.lpToken));
    }
    return lpTokens;
}
//# sourceMappingURL=HubPool.Fixture.js.map