import "@nomiclabs/hardhat-ethers";
import "@openzeppelin/hardhat-upgrades";
import hre from "hardhat";
import { ethers as ethersLib } from "ethers";
import { getContractFactory } from "../utils/getContractFactory";
import { amountToDeposit, depositRelayerFeePct, destinationChainId, maxUint256, realizedLpFeePct, repaymentChainId, TokenRolesEnum, zeroAddress, randomAddress, } from "../constants";
import { createFixture } from "./utils";
const { defaultAbiCoder, keccak256 } = ethersLib.utils;
export { zeroAddress };
// ---------------------------------------------------------------------------
// Relay hash helpers
// ---------------------------------------------------------------------------
export function getRelayHash(_depositor, _recipient, _depositId, _originChainId, _destinationChainId, _destinationToken, _amount, _realizedLpFeePct, _relayerFeePct, _message) {
    const relayData = {
        depositor: _depositor,
        recipient: _recipient,
        destinationToken: _destinationToken,
        amount: _amount || amountToDeposit,
        originChainId: _originChainId.toString(),
        destinationChainId: _destinationChainId.toString(),
        realizedLpFeePct: _realizedLpFeePct || realizedLpFeePct,
        relayerFeePct: _relayerFeePct || depositRelayerFeePct,
        depositId: _depositId.toString(),
        message: _message || "0x",
    };
    const relayHash = keccak256(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 };
}
export function getV3RelayHash(relayData, destChainId) {
    return keccak256(defaultAbiCoder.encode([
        "tuple(bytes32 depositor, bytes32 recipient, bytes32 exclusiveRelayer, bytes32 inputToken, bytes32 outputToken, uint256 inputAmount, uint256 outputAmount, uint256 originChainId, uint256 depositId, uint32 fillDeadline, uint32 exclusivityDeadline, bytes message)",
        "uint256 destinationChainId",
    ], [relayData, destChainId]));
}
export function getLegacyV3RelayHash(relayData, destChainId) {
    return keccak256(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, destChainId]));
}
// ---------------------------------------------------------------------------
// Parameter builders
// ---------------------------------------------------------------------------
export function getDepositParams(args) {
    return [
        args.recipient ?? randomAddress(),
        args.originToken,
        args.amount.toString(),
        args.destinationChainId.toString(),
        args.relayerFeePct.toString(),
        args.quoteTimestamp.toString(),
        args.message ?? "0x",
        args?.maxCount?.toString() ?? maxUint256.toString(),
    ];
}
export function getFillRelayParams(_relayData, _maxTokensToSend, _repaymentChain, _maxCount) {
    return [
        _relayData.depositor,
        _relayData.recipient,
        _relayData.destinationToken,
        _relayData.amount.toString(),
        _maxTokensToSend.toString(),
        _repaymentChain ? _repaymentChain.toString() : repaymentChainId.toString(),
        _relayData.originChainId,
        _relayData.realizedLpFeePct.toString(),
        _relayData.relayerFeePct.toString(),
        _relayData.depositId,
        _relayData.message || "0x",
        _maxCount ? _maxCount.toString() : maxUint256.toString(),
    ];
}
export 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() : repaymentChainId.toString(),
        _relayData.originChainId,
        _relayData.realizedLpFeePct.toString(),
        _relayData.relayerFeePct.toString(),
        _updatedFee.toString(),
        _relayData.depositId,
        _relayData.message,
        _updatedMessage || _relayData.message,
        _signature,
        _maxCount ? _maxCount.toString() : maxUint256.toString(),
    ];
}
export 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,
    ];
}
// ---------------------------------------------------------------------------
// EIP-712 signature helpers
// ---------------------------------------------------------------------------
export 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 };
}
export async function getUpdatedV3DepositSignature(depositor, depositId, originChainId, updatedOutputAmount, updatedRecipient, updatedMessage) {
    const typedData = {
        types: {
            UpdateDepositDetails: [
                { name: "depositId", type: "uint256" },
                { name: "originChainId", type: "uint256" },
                { name: "updatedOutputAmount", type: "uint256" },
                { name: "updatedRecipient", type: "bytes32" },
                { 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);
}
// ---------------------------------------------------------------------------
// Mock deployers
// ---------------------------------------------------------------------------
export async function deployMockSpokePoolCaller(spokePool, rootBundleId, leaf, proof) {
    return await (await getContractFactory("MockCaller", (await hre.ethers.getSigners())[0])).deploy(spokePool.address, rootBundleId, leaf, proof);
}
// ---------------------------------------------------------------------------
// Deployment
// ---------------------------------------------------------------------------
/**
 * Deploys a SpokePool with associated tokens for testing.
 * This is a local implementation that uses our local getContractFactory
 * instead of the one from @across-protocol/contracts.
 */
export async function deploySpokePool(ethers, spokePoolName = "MockSpokePool") {
    const [deployerWallet, crossChainAdmin, hubPool] = await ethers.getSigners();
    // Create tokens
    const weth = await (await getContractFactory("WETH9", deployerWallet)).deploy();
    const erc20 = await (await getContractFactory("ExpandedERC20", deployerWallet)).deploy("USD Coin", "USDC", 18);
    await erc20.addMember(TokenRolesEnum.MINTER, deployerWallet.address);
    const unwhitelistedErc20 = await (await getContractFactory("ExpandedERC20", deployerWallet)).deploy("Unwhitelisted", "UNWHITELISTED", 18);
    await unwhitelistedErc20.addMember(TokenRolesEnum.MINTER, deployerWallet.address);
    const destErc20 = await (await getContractFactory("ExpandedERC20WithBlacklist", deployerWallet)).deploy("L2 USD Coin", "L2 USDC", 18);
    await destErc20.addMember(TokenRolesEnum.MINTER, deployerWallet.address);
    // Deploy the pool using hardhat upgrades
    const spokePool = await hre.upgrades.deployProxy(await getContractFactory(spokePoolName, deployerWallet), [0, crossChainAdmin.address, hubPool.address], { kind: "uups", unsafeAllow: ["delegatecall"], constructorArgs: [weth.address] });
    await spokePool.setChainId(destinationChainId);
    // ERC1271
    const erc1271 = await (await getContractFactory("MockERC1271", deployerWallet)).deploy(deployerWallet.address);
    return {
        weth,
        erc20,
        spokePool,
        unwhitelistedErc20,
        destErc20,
        erc1271,
    };
}
export const spokePoolFixture = createFixture(async () => {
    return await deploySpokePool(hre.ethers);
});
//# sourceMappingURL=SpokePool.Fixture.js.map