"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.spokePoolFixture = void 0;
exports.deploySpokePool = deploySpokePool;
exports.enableRoutes = enableRoutes;
exports.getRelayHash = getRelayHash;
exports.getV3RelayHash = getV3RelayHash;
exports.getDepositParams = getDepositParams;
exports.getFillRelayParams = getFillRelayParams;
exports.getFillRelayUpdatedFeeParams = getFillRelayUpdatedFeeParams;
exports.getExecuteSlowRelayParams = getExecuteSlowRelayParams;
exports.modifyRelayHelper = modifyRelayHelper;
exports.getUpdatedV3DepositSignature = getUpdatedV3DepositSignature;
exports.deployMockSpokePoolCaller = deployMockSpokePoolCaller;
const utils_hre_1 = require("../../../../utils/utils.hre");
const utils_1 = require("../../../../utils/utils");
const consts = __importStar(require("../constants"));
exports.spokePoolFixture = utils_hre_1.hre.deployments.createFixture(async ({ ethers }) => {
    return await deploySpokePool(ethers);
});
// Have a separate function that deploys the contract and returns the contract addresses. This is called by the fixture
// to have standard fixture features. It is also exported as a function to enable non-snapshoted deployments.
async function deploySpokePool(ethers, spokePoolName = "MockSpokePool") {
    const [deployerWallet, crossChainAdmin, hubPool] = await ethers.getSigners();
    // Create tokens:
    const weth = await (await (0, utils_1.getContractFactory)("WETH9", deployerWallet)).deploy();
    const erc20 = await (await (0, utils_1.getContractFactory)("ExpandedERC20", deployerWallet)).deploy("USD Coin", "USDC", 18);
    await erc20.addMember(consts.TokenRolesEnum.MINTER, deployerWallet.address);
    const unwhitelistedErc20 = await (await (0, utils_1.getContractFactory)("ExpandedERC20", deployerWallet)).deploy("Unwhitelisted", "UNWHITELISTED", 18);
    await unwhitelistedErc20.addMember(consts.TokenRolesEnum.MINTER, deployerWallet.address);
    const destErc20 = await (await (0, utils_1.getContractFactory)("ExpandedERC20", deployerWallet)).deploy("L2 USD Coin", "L2 USDC", 18);
    await destErc20.addMember(consts.TokenRolesEnum.MINTER, deployerWallet.address);
    // Deploy the pool
    const spokePool = await utils_hre_1.hre.upgrades.deployProxy(await (0, utils_1.getContractFactory)(spokePoolName, deployerWallet), [0, crossChainAdmin.address, hubPool.address], { kind: "uups", unsafeAllow: ["delegatecall"], constructorArgs: [weth.address] });
    await spokePool.setChainId(consts.destinationChainId);
    // ERC1271
    const erc1271 = await (await (0, utils_1.getContractFactory)("MockERC1271", deployerWallet)).deploy(deployerWallet.address);
    return {
        weth,
        erc20,
        spokePool,
        unwhitelistedErc20,
        destErc20,
        erc1271,
    };
}
async function enableRoutes(spokePool, routes) {
    for (const route of routes) {
        await spokePool.setEnableRoute(route.originToken, route.destinationChainId ?? consts.destinationChainId, route.enabled ?? true);
    }
}
function getRelayHash(_depositor, _recipient, _depositId, _originChainId, _destinationChainId, _destinationToken, _amount, _realizedLpFeePct, _relayerFeePct, _message) {
    const relayData = {
        depositor: _depositor,
        recipient: _recipient,
        destinationToken: _destinationToken,
        amount: _amount || consts.amountToDeposit,
        originChainId: _originChainId.toString(),
        destinationChainId: _destinationChainId.toString(),
        realizedLpFeePct: _realizedLpFeePct || consts.realizedLpFeePct,
        relayerFeePct: _relayerFeePct || consts.depositRelayerFeePct,
        depositId: _depositId.toString(),
        message: _message || "0x",
    };
    const relayHash = utils_1.ethers.utils.keccak256(utils_1.defaultAbiCoder.encode([
        "tuple(address depositor, address recipient, address destinationToken, uint256 amount, uint256 originChainId, uint256 destinationChainId, int64 realizedLpFeePct, int64 relayerFeePct, uint32 depositId, bytes message)",
    ], [relayData]));
    return { relayHash, relayData };
}
function getV3RelayHash(relayData, destinationChainId) {
    return utils_1.ethers.utils.keccak256(utils_1.defaultAbiCoder.encode([
        "tuple(address depositor, address recipient, address exclusiveRelayer, address inputToken, address outputToken, uint256 inputAmount, uint256 outputAmount, uint256 originChainId, uint32 depositId, uint32 fillDeadline, uint32 exclusivityDeadline, bytes message)",
        "uint256 destinationChainId",
    ], [relayData, destinationChainId]));
}
function getDepositParams(args) {
    return [
        args.recipient ?? (0, utils_1.randomAddress)(),
        args.originToken,
        args.amount.toString(),
        args.destinationChainId.toString(),
        args.relayerFeePct.toString(),
        args.quoteTimestamp.toString(),
        args.message ?? "0x",
        args?.maxCount?.toString() ?? consts.maxUint256.toString(),
    ];
}
function getFillRelayParams(_relayData, _maxTokensToSend, _repaymentChain, _maxCount) {
    return [
        _relayData.depositor,
        _relayData.recipient,
        _relayData.destinationToken,
        _relayData.amount.toString(),
        _maxTokensToSend.toString(),
        _repaymentChain ? _repaymentChain.toString() : consts.repaymentChainId.toString(),
        _relayData.originChainId,
        _relayData.realizedLpFeePct.toString(),
        _relayData.relayerFeePct.toString(),
        _relayData.depositId,
        _relayData.message || "0x",
        _maxCount ? _maxCount.toString() : consts.maxUint256.toString(),
    ];
}
function getFillRelayUpdatedFeeParams(_relayData, _maxTokensToSend, _updatedFee, _signature, _repaymentChain, _updatedRecipient, _updatedMessage, _maxCount) {
    return [
        _relayData.depositor,
        _relayData.recipient,
        _updatedRecipient || _relayData.recipient,
        _relayData.destinationToken,
        _relayData.amount.toString(),
        _maxTokensToSend.toString(),
        _repaymentChain ? _repaymentChain.toString() : consts.repaymentChainId.toString(),
        _relayData.originChainId,
        _relayData.realizedLpFeePct.toString(),
        _relayData.relayerFeePct.toString(),
        _updatedFee.toString(),
        _relayData.depositId,
        _relayData.message,
        _updatedMessage || _relayData.message,
        _signature,
        _maxCount ? _maxCount.toString() : consts.maxUint256.toString(),
    ];
}
function getExecuteSlowRelayParams(_depositor, _recipient, _destToken, _amount, _originChainId, _realizedLpFeePct, _relayerFeePct, _depositId, _relayerRefundId, _message, _payoutAdjustment, _proof) {
    return [
        _depositor,
        _recipient,
        _destToken,
        _amount.toString(),
        _originChainId.toString(),
        _realizedLpFeePct.toString(),
        _relayerFeePct.toString(),
        _depositId.toString(),
        _relayerRefundId.toString(),
        _message,
        _payoutAdjustment.toString(),
        _proof,
    ];
}
async function modifyRelayHelper(modifiedRelayerFeePct, depositId, originChainId, depositor, updatedRecipient, updatedMessage) {
    const typedData = {
        types: {
            UpdateDepositDetails: [
                { name: "depositId", type: "uint32" },
                { name: "originChainId", type: "uint256" },
                { name: "updatedRelayerFeePct", type: "int64" },
                { name: "updatedRecipient", type: "address" },
                { name: "updatedMessage", type: "bytes" },
            ],
        },
        domain: {
            name: "ACROSS-V2",
            version: "1.0.0",
            chainId: Number(originChainId),
        },
        message: {
            depositId,
            originChainId,
            updatedRelayerFeePct: modifiedRelayerFeePct,
            updatedRecipient,
            updatedMessage,
        },
    };
    const signature = await depositor._signTypedData(typedData.domain, typedData.types, typedData.message);
    return {
        signature,
    };
}
async function getUpdatedV3DepositSignature(depositor, depositId, originChainId, updatedOutputAmount, updatedRecipient, updatedMessage) {
    const typedData = {
        types: {
            UpdateDepositDetails: [
                { name: "depositId", type: "uint32" },
                { name: "originChainId", type: "uint256" },
                { name: "updatedOutputAmount", type: "uint256" },
                { name: "updatedRecipient", type: "address" },
                { name: "updatedMessage", type: "bytes" },
            ],
        },
        domain: {
            name: "ACROSS-V2",
            version: "1.0.0",
            chainId: originChainId,
        },
        message: {
            depositId,
            originChainId,
            updatedOutputAmount,
            updatedRecipient,
            updatedMessage,
        },
    };
    return await depositor._signTypedData(typedData.domain, typedData.types, typedData.message);
}
async function deployMockSpokePoolCaller(spokePool, rootBundleId, leaf, proof) {
    return await (await (0, utils_1.getContractFactory)("MockCaller", (await utils_1.ethers.getSigners())[0])).deploy(spokePool.address, rootBundleId, leaf, proof);
}
