"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const constants_1 = require("../constants");
const utils_1 = require("../../utils/utils");
const utils_hre_1 = require("../../utils/utils.hre");
const HubPool_Fixture_1 = require("../fixtures/HubPool.Fixture");
const MerkleLib_utils_1 = require("../MerkleLib.utils");
const NO_ADMIN_REVERT = "Sender must be admin";
const gatewayRouterABI = [
    {
        inputs: [],
        name: "defaultERC20Gateway",
        outputs: [
            {
                internalType: "address",
                name: "",
                type: "address",
            },
        ],
        stateMutability: "view",
        type: "function",
    },
    {
        inputs: [
            {
                internalType: "address",
                name: "_token",
                type: "address",
            },
        ],
        name: "getERC20Gateway",
        outputs: [
            {
                internalType: "address",
                name: "",
                type: "address",
            },
        ],
        stateMutability: "view",
        type: "function",
    },
    {
        inputs: [
            {
                internalType: "address",
                name: "_token",
                type: "address",
            },
            {
                internalType: "address",
                name: "_to",
                type: "address",
            },
            {
                internalType: "uint256",
                name: "_amount",
                type: "uint256",
            },
            {
                internalType: "uint256",
                name: "_gasLimit",
                type: "uint256",
            },
        ],
        name: "withdrawERC20",
        outputs: [],
        stateMutability: "payable",
        type: "function",
    },
];
const messengerABI = [
    {
        inputs: [],
        name: "xDomainMessageSender",
        outputs: [
            {
                internalType: "address",
                name: "",
                type: "address",
            },
        ],
        stateMutability: "view",
        type: "function",
    },
];
/**
 * For equivalency with Smock, we need to use the same BigNumber type.
 * @param value A string or number to convert to a BigNumber
 * @returns A BigNumber
 */
function toBN(value) {
    return utils_1.ethers.BigNumber.from(value);
}
let hubPool, scrollSpokePool, dai, weth;
let owner, relayer, rando;
let l2GatewayRouter, l2Messenger;
describe("Scroll Spoke Pool", function () {
    beforeEach(async function () {
        [owner, relayer, rando] = await utils_1.ethers.getSigners();
        ({ weth, dai, hubPool } = await (0, HubPool_Fixture_1.hubPoolFixture)());
        // Create the fake messenger and l2gateway router.
        l2GatewayRouter = await (0, utils_1.createFakeFromABI)(gatewayRouterABI);
        l2Messenger = await (0, utils_1.createFakeFromABI)(messengerABI);
        scrollSpokePool = await utils_hre_1.hre.upgrades.deployProxy(await (0, utils_1.getContractFactory)("Scroll_SpokePool", owner), [l2GatewayRouter.address, l2Messenger.address, 0, owner.address, hubPool.address], { kind: "uups", unsafeAllow: ["delegatecall"], constructorArgs: [weth.address, 3600, 7200] });
        await (0, utils_1.seedContract)(scrollSpokePool, relayer, [dai], weth, constants_1.amountHeldByPool);
    });
    it("Only cross domain owner upgrade logic contract", async function () {
        // TODO: Could also use upgrades.prepareUpgrade but I'm unclear of differences
        const implementation = await utils_hre_1.hre.upgrades.deployImplementation(await (0, utils_1.getContractFactory)("Scroll_SpokePool", owner), { kind: "uups", unsafeAllow: ["delegatecall"], constructorArgs: [weth.address, 60 * 60, 9 * 60 * 60] });
        await (0, utils_1.expect)(scrollSpokePool.connect(rando).upgradeTo(implementation)).to.be.revertedWith(NO_ADMIN_REVERT);
        l2Messenger.xDomainMessageSender.returns(owner.address);
        await scrollSpokePool.connect(owner).upgradeTo(implementation);
    });
    it("Only cross domain owner can set the new L2GatewayRouter", async function () {
        const newL2GatewayRouter = (0, utils_1.randomAddress)();
        await (0, utils_1.expect)(scrollSpokePool.connect(rando).setL2GatewayRouter(rando.address)).to.be.reverted;
        l2Messenger.xDomainMessageSender.returns(owner.address);
        await (0, utils_1.expect)(scrollSpokePool.connect(owner).setL2GatewayRouter(newL2GatewayRouter)).to.not.be.reverted;
        const resolvedNewL2GatewayRouter = await scrollSpokePool.l2GatewayRouter();
        (0, utils_1.expect)(resolvedNewL2GatewayRouter).to.equal(newL2GatewayRouter);
    });
    it("Only cross domain owner can set the new L2Messenger", async function () {
        const newL2Messenger = (0, utils_1.randomAddress)();
        await (0, utils_1.expect)(scrollSpokePool.connect(rando).setL2ScrollMessenger(rando.address)).to.be.reverted;
        l2Messenger.xDomainMessageSender.returns(owner.address);
        await (0, utils_1.expect)(scrollSpokePool.connect(owner).setL2ScrollMessenger(newL2Messenger)).to.not.be.reverted;
        const resolvedNewL2Messenger = await scrollSpokePool.l2ScrollMessenger();
        (0, utils_1.expect)(resolvedNewL2Messenger).to.equal(newL2Messenger);
    });
    it("Only cross domain owner can relay admin root bundles", async function () {
        const { tree } = await (0, MerkleLib_utils_1.constructSingleRelayerRefundTree)(dai.address, await scrollSpokePool.callStatic.chainId());
        await (0, utils_1.expect)(scrollSpokePool.relayRootBundle(tree.getHexRoot(), constants_1.mockTreeRoot)).to.be.revertedWith(NO_ADMIN_REVERT);
    });
    // *ALL* ERC20 (including WETH) will be bridged through the withdrawERC20 method.
    it("Bridge tokens to hub pool correctly calls the L2GatewayRouter for ERC20", async function () {
        const { leaves, tree } = await (0, MerkleLib_utils_1.constructSingleRelayerRefundTree)(dai.address, await scrollSpokePool.callStatic.chainId());
        const amountToReturn = leaves[0].amountToReturn;
        l2Messenger.xDomainMessageSender.returns(owner.address);
        await scrollSpokePool.connect(owner).relayRootBundle(tree.getHexRoot(), constants_1.mockTreeRoot);
        l2Messenger.xDomainMessageSender.reset();
        await scrollSpokePool.connect(relayer).executeRelayerRefundLeaf(0, leaves[0], tree.getHexProof(leaves[0]));
        // This should have sent tokens back to L1. Check the correct methods on the gateway are correctly called.
        (0, utils_1.expect)(l2GatewayRouter.withdrawERC20).to.have.been.calledWith(dai.address, hubPool.address, toBN(amountToReturn.toString()), toBN(0));
    });
});
