"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable no-unused-expressions */
const constants_1 = require("./../constants");
const utils_1 = require("../../../../utils/utils");
const HubPool_Fixture_1 = require("../fixtures/HubPool.Fixture");
const MerkleLib_utils_1 = require("../MerkleLib.utils");
const abis_1 = require("../../../../utils/abis");
let hubPool, solanaAdapter, weth, usdc, timer, mockSpoke;
let owner, dataWorker, liquidityProvider;
let cctpTokenMessenger, cctpMessageTransmitter, cctpTokenMinter;
let solanaSpokePoolBytes32, solanaUsdcBytes32, solanaSpokePoolUsdcVaultBytes32, solanaSpokePoolAddress, solanaUsdcAddress;
const solanaChainId = 1234567890; // TODO: Decide how to represent Solana in Across as it does not have a chainId.
const solanaDomainId = 5;
describe("Solana Chain Adapter", function () {
    beforeEach(async function () {
        [owner, dataWorker, liquidityProvider] = await utils_1.ethers.getSigners();
        ({ weth, hubPool, mockSpoke, timer, usdc } = await (0, HubPool_Fixture_1.hubPoolFixture)());
        await (0, utils_1.seedWallet)(dataWorker, [usdc], weth, constants_1.amountToLp);
        await (0, utils_1.seedWallet)(liquidityProvider, [usdc], weth, constants_1.amountToLp.mul(10));
        await (0, HubPool_Fixture_1.enableTokensForLP)(owner, hubPool, weth, [weth, usdc]);
        for (const token of [weth, usdc]) {
            await token.connect(liquidityProvider).approve(hubPool.address, constants_1.amountToLp);
            await hubPool.connect(liquidityProvider).addLiquidity(token.address, constants_1.amountToLp);
            await token.connect(dataWorker).approve(hubPool.address, constants_1.bondAmount.mul(10));
        }
        cctpTokenMessenger = await (0, utils_1.createFakeFromABI)(abis_1.CCTPTokenMessengerInterface);
        cctpMessageTransmitter = await (0, utils_1.createFakeFromABI)(abis_1.CCTPMessageTransmitterInterface);
        cctpTokenMinter = await (0, utils_1.createFakeFromABI)(abis_1.CCTPTokenMinterInterface);
        cctpTokenMessenger.localMinter.returns(cctpTokenMinter.address);
        cctpTokenMinter.burnLimitsPerMessage.returns((0, utils_1.toWeiWithDecimals)("1000000", 6));
        solanaSpokePoolBytes32 = (0, utils_1.createRandomBytes32)();
        solanaUsdcBytes32 = (0, utils_1.createRandomBytes32)();
        solanaSpokePoolUsdcVaultBytes32 = (0, utils_1.createRandomBytes32)();
        solanaSpokePoolAddress = (0, utils_1.trimSolanaAddress)(solanaSpokePoolBytes32);
        solanaUsdcAddress = (0, utils_1.trimSolanaAddress)(solanaUsdcBytes32);
        solanaAdapter = await (await (0, utils_1.getContractFactory)("Solana_Adapter", owner)).deploy(usdc.address, cctpTokenMessenger.address, cctpMessageTransmitter.address, solanaSpokePoolBytes32, solanaUsdcBytes32, solanaSpokePoolUsdcVaultBytes32);
        await hubPool.setCrossChainContracts(solanaChainId, solanaAdapter.address, solanaSpokePoolAddress);
        await hubPool.setPoolRebalanceRoute(solanaChainId, usdc.address, solanaUsdcAddress);
    });
    it("relayMessage calls spoke pool functions", async function () {
        const newAdmin = (0, utils_1.randomAddress)();
        const functionCallData = mockSpoke.interface.encodeFunctionData("setCrossDomainAdmin", [newAdmin]);
        (0, utils_1.expect)(await hubPool.relaySpokePoolAdminFunction(solanaChainId, functionCallData))
            .to.emit(solanaAdapter.attach(hubPool.address), "MessageRelayed")
            .withArgs(solanaSpokePoolAddress.toLowerCase(), functionCallData);
        (0, utils_1.expect)(cctpMessageTransmitter.sendMessage).to.have.been.calledWith(solanaDomainId, solanaSpokePoolBytes32, functionCallData);
    });
    it("Correctly calls the CCTP bridge adapter when attempting to bridge USDC", async function () {
        // Create an action that will send an L1->L2 tokens transfer and bundle. For this, create a relayer repayment bundle
        // and check that at it's finalization the L2 bridge contracts are called as expected.
        const { leaves, tree, tokensSendToL2 } = await (0, MerkleLib_utils_1.constructSingleChainTree)(usdc.address, 1, solanaChainId, 6);
        await hubPool
            .connect(dataWorker)
            .proposeRootBundle([3117], 1, tree.getHexRoot(), constants_1.mockRelayerRefundRoot, constants_1.mockSlowRelayRoot);
        await timer.setCurrentTime(Number(await timer.getCurrentTime()) + constants_1.refundProposalLiveness + 1);
        await hubPool.connect(dataWorker).executeRootBundle(...Object.values(leaves[0]), tree.getHexProof(leaves[0]));
        // Adapter should have approved CCTP TokenMessenger to spend its ERC20, but the fake instance does not pull them.
        (0, utils_1.expect)(await usdc.allowance(hubPool.address, cctpTokenMessenger.address)).to.equal(tokensSendToL2);
        // The correct functions should have been called on the CCTP TokenMessenger contract
        (0, utils_1.expect)(cctpTokenMessenger.depositForBurn).to.have.been.calledOnce;
        (0, utils_1.expect)(cctpTokenMessenger.depositForBurn).to.have.been.calledWith(utils_1.ethers.BigNumber.from(tokensSendToL2), solanaDomainId, solanaSpokePoolUsdcVaultBytes32, usdc.address);
    });
    it("Correctly translates setEnableRoute calls to the spoke pool", async function () {
        // Enable deposits for USDC on Solana.
        const destinationChainId = 1;
        const depositsEnabled = true;
        await hubPool.setDepositRoute(solanaChainId, destinationChainId, solanaUsdcAddress, depositsEnabled);
        // Solana spoke pool expects to receive full bytes32 token address and uint64 for chainId.
        const solanaInterface = new utils_1.ethers.utils.Interface(["function setEnableRoute(bytes32, uint64, bool)"]);
        const solanaMessage = solanaInterface.encodeFunctionData("setEnableRoute", [
            solanaUsdcBytes32,
            destinationChainId,
            depositsEnabled,
        ]);
        (0, utils_1.expect)(cctpMessageTransmitter.sendMessage).to.have.been.calledWith(solanaDomainId, solanaSpokePoolBytes32, solanaMessage);
    });
});
