"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isBytes32 = exports.bytes32ToAddress = exports.addressToBytes = exports.hexZeroPad = exports.hexToUtf8 = exports.fromWei = exports.toBNWeiWithDecimals = exports.toWeiWithDecimals = exports.Signer = exports.keccak256 = exports.defaultAbiCoder = exports.winston = exports.utf8ToHex = exports.toWei = exports.toBNWei = exports.toBN = exports.sinon = exports.expect = exports.chaiAssert = exports.chai = exports.Contract = exports.BigNumber = exports.merkleLibFixture = exports.deploySpokePool = exports.spokePoolFixture = exports.deployHubPool = exports.hubPoolFixture = exports.getContractFactory = exports.constructSingleChainTree = exports.constructSingleRelayerRefundTree = exports.getParamType = exports.buildV3SlowRelayTree = exports.buildSlowRelayTree = exports.buildRelayerRefundLeaves = exports.buildRelayerRefundTree = exports.buildPoolRebalanceLeaves = exports.buildPoolRebalanceLeafTree = exports.zeroAddress = exports.randomAddress = exports.deployMockSpokePoolCaller = exports.getExecuteSlowRelayParams = exports.getFillRelayUpdatedFeeParams = exports.getFillRelayParams = exports.getLegacyV3RelayHash = exports.getV3RelayHash = exports.getRelayHash = exports.modifyRelayHelper = exports.getUpdatedV3DepositSignature = exports.getDepositParams = exports.ethers = void 0;
exports.createRandomBytes32 = void 0;
exports.randomBigNumber = randomBigNumber;
exports.randomBytes32 = randomBytes32;
exports.seedWallet = seedWallet;
exports.seedContract = seedContract;
exports.trimSolanaAddress = trimSolanaAddress;
exports.hashNonEmptyMessage = hashNonEmptyMessage;
exports.deepEqualsWithBigNumber = deepEqualsWithBigNumber;
exports.assertPromiseError = assertPromiseError;
exports.assertPromisePasses = assertPromisePasses;
exports.setupTokensForWallet = setupTokensForWallet;
exports.createSpyLogger = createSpyLogger;
exports.deploySpokePoolWithToken = deploySpokePoolWithToken;
exports.deployConfigStore = deployConfigStore;
exports.deployAndConfigureHubPool = deployAndConfigureHubPool;
exports.enableRoutesOnHubPool = enableRoutesOnHubPool;
exports.appendMessageToResult = appendMessageToResult;
exports.getLastBlockTime = getLastBlockTime;
exports.addLiquidity = addLiquidity;
exports.deposit = deposit;
exports.depositV3 = depositV3;
exports.requestV3SlowFill = requestV3SlowFill;
exports.fillRelay = fillRelay;
exports.getLastBlockNumber = getLastBlockNumber;
exports.convertMockedConfigClient = convertMockedConfigClient;
exports.bigNumberFormatter = bigNumberFormatter;
exports.buildDepositForRelayerFeeTest = buildDepositForRelayerFeeTest;
const tslib_1 = require("tslib");
const assert_1 = tslib_1.__importDefault(require("assert"));
const chai_1 = tslib_1.__importStar(require("chai"));
exports.chai = chai_1.default;
Object.defineProperty(exports, "expect", { enumerable: true, get: function () { return chai_1.expect; } });
const chai_exclude_1 = tslib_1.__importDefault(require("chai-exclude"));
const ethers_1 = require("ethers");
Object.defineProperty(exports, "ethers", { enumerable: true, get: function () { return ethers_1.ethers; } });
Object.defineProperty(exports, "Contract", { enumerable: true, get: function () { return ethers_1.Contract; } });
Object.defineProperty(exports, "Signer", { enumerable: true, get: function () { return ethers_1.Signer; } });
const hardhat_1 = require("hardhat");
const lodash_1 = tslib_1.__importDefault(require("lodash"));
const sinon_1 = tslib_1.__importDefault(require("sinon"));
exports.sinon = sinon_1.default;
const winston_1 = tslib_1.__importDefault(require("winston"));
exports.winston = winston_1.default;
const clients_1 = require("../../src/clients");
const constants_1 = require("../../src/constants");
const utils_1 = require("../../src/utils");
Object.defineProperty(exports, "BigNumber", { enumerable: true, get: function () { return utils_1.BigNumber; } });
Object.defineProperty(exports, "toBN", { enumerable: true, get: function () { return utils_1.toBN; } });
Object.defineProperty(exports, "toBNWei", { enumerable: true, get: function () { return utils_1.toBNWei; } });
Object.defineProperty(exports, "toWei", { enumerable: true, get: function () { return utils_1.toWei; } });
Object.defineProperty(exports, "utf8ToHex", { enumerable: true, get: function () { return utils_1.utf8ToHex; } });
const constants_2 = require("../constants");
Object.defineProperty(exports, "randomAddress", { enumerable: true, get: function () { return constants_2.randomAddress; } });
Object.defineProperty(exports, "zeroAddress", { enumerable: true, get: function () { return constants_2.zeroAddress; } });
const SpyTransport_1 = require("./SpyTransport");
chai_1.default.use(chai_exclude_1.default);
const chaiAssert = chai_1.default.assert;
exports.chaiAssert = chaiAssert;
var SpokePool_Fixture_1 = require("../fixtures/SpokePool.Fixture");
Object.defineProperty(exports, "getDepositParams", { enumerable: true, get: function () { return SpokePool_Fixture_1.getDepositParams; } });
Object.defineProperty(exports, "getUpdatedV3DepositSignature", { enumerable: true, get: function () { return SpokePool_Fixture_1.getUpdatedV3DepositSignature; } });
Object.defineProperty(exports, "modifyRelayHelper", { enumerable: true, get: function () { return SpokePool_Fixture_1.modifyRelayHelper; } });
Object.defineProperty(exports, "getRelayHash", { enumerable: true, get: function () { return SpokePool_Fixture_1.getRelayHash; } });
Object.defineProperty(exports, "getV3RelayHash", { enumerable: true, get: function () { return SpokePool_Fixture_1.getV3RelayHash; } });
Object.defineProperty(exports, "getLegacyV3RelayHash", { enumerable: true, get: function () { return SpokePool_Fixture_1.getLegacyV3RelayHash; } });
Object.defineProperty(exports, "getFillRelayParams", { enumerable: true, get: function () { return SpokePool_Fixture_1.getFillRelayParams; } });
Object.defineProperty(exports, "getFillRelayUpdatedFeeParams", { enumerable: true, get: function () { return SpokePool_Fixture_1.getFillRelayUpdatedFeeParams; } });
Object.defineProperty(exports, "getExecuteSlowRelayParams", { enumerable: true, get: function () { return SpokePool_Fixture_1.getExecuteSlowRelayParams; } });
Object.defineProperty(exports, "deployMockSpokePoolCaller", { enumerable: true, get: function () { return SpokePool_Fixture_1.deployMockSpokePoolCaller; } });
var MerkleLib_utils_1 = require("./MerkleLib.utils");
Object.defineProperty(exports, "buildPoolRebalanceLeafTree", { enumerable: true, get: function () { return MerkleLib_utils_1.buildPoolRebalanceLeafTree; } });
Object.defineProperty(exports, "buildPoolRebalanceLeaves", { enumerable: true, get: function () { return MerkleLib_utils_1.buildPoolRebalanceLeaves; } });
Object.defineProperty(exports, "buildRelayerRefundTree", { enumerable: true, get: function () { return MerkleLib_utils_1.buildRelayerRefundTree; } });
Object.defineProperty(exports, "buildRelayerRefundLeaves", { enumerable: true, get: function () { return MerkleLib_utils_1.buildRelayerRefundLeaves; } });
Object.defineProperty(exports, "buildSlowRelayTree", { enumerable: true, get: function () { return MerkleLib_utils_1.buildSlowRelayTree; } });
Object.defineProperty(exports, "buildV3SlowRelayTree", { enumerable: true, get: function () { return MerkleLib_utils_1.buildV3SlowRelayTree; } });
Object.defineProperty(exports, "getParamType", { enumerable: true, get: function () { return MerkleLib_utils_1.getParamType; } });
Object.defineProperty(exports, "constructSingleRelayerRefundTree", { enumerable: true, get: function () { return MerkleLib_utils_1.constructSingleRelayerRefundTree; } });
Object.defineProperty(exports, "constructSingleChainTree", { enumerable: true, get: function () { return MerkleLib_utils_1.constructSingleChainTree; } });
const getContractFactory_1 = require("./getContractFactory");
Object.defineProperty(exports, "getContractFactory", { enumerable: true, get: function () { return getContractFactory_1.getContractFactory; } });
const HubPool_Fixture_1 = require("../fixtures/HubPool.Fixture");
Object.defineProperty(exports, "hubPoolFixture", { enumerable: true, get: function () { return HubPool_Fixture_1.hubPoolFixture; } });
Object.defineProperty(exports, "deployHubPool", { enumerable: true, get: function () { return HubPool_Fixture_1.deployHubPool; } });
const SpokePool_Fixture_2 = require("../fixtures/SpokePool.Fixture");
Object.defineProperty(exports, "spokePoolFixture", { enumerable: true, get: function () { return SpokePool_Fixture_2.spokePoolFixture; } });
Object.defineProperty(exports, "deploySpokePool", { enumerable: true, get: function () { return SpokePool_Fixture_2.deploySpokePool; } });
var MerkleLib_Fixture_1 = require("../fixtures/MerkleLib.Fixture");
Object.defineProperty(exports, "merkleLibFixture", { enumerable: true, get: function () { return MerkleLib_Fixture_1.merkleLibFixture; } });
const { defaultAbiCoder, keccak256 } = ethers_1.ethers.utils;
exports.defaultAbiCoder = defaultAbiCoder;
exports.keccak256 = keccak256;
const toWeiWithDecimals = (num, decimals) => ethers_1.ethers.utils.parseUnits(num.toString(), decimals);
exports.toWeiWithDecimals = toWeiWithDecimals;
const toBNWeiWithDecimals = (num, decimals) => utils_1.BigNumber.from((0, exports.toWeiWithDecimals)(num, decimals));
exports.toBNWeiWithDecimals = toBNWeiWithDecimals;
const fromWei = (num) => ethers_1.ethers.utils.formatUnits(num.toString());
exports.fromWei = fromWei;
const hexToUtf8 = (input) => ethers_1.ethers.utils.toUtf8String(input);
exports.hexToUtf8 = hexToUtf8;
const hexZeroPad = (input, length) => ethers_1.ethers.utils.hexZeroPad(input, length);
exports.hexZeroPad = hexZeroPad;
const addressToBytes = (input) => (0, exports.hexZeroPad)(input.toLowerCase(), 32);
exports.addressToBytes = addressToBytes;
const bytes32ToAddress = (input) => {
    if (!/^0x[a-fA-F0-9]{64}$/.test(input)) {
        throw new Error("Invalid bytes32 input");
    }
    return ethers_1.ethers.utils.getAddress("0x" + input.slice(26));
};
exports.bytes32ToAddress = bytes32ToAddress;
const isBytes32 = (input) => /^0x[0-9a-fA-F]{64}$/.test(input);
exports.isBytes32 = isBytes32;
function randomBigNumber(bytes = 32, signed = false) {
    const sign = signed && Math.random() < 0.5 ? "-" : "";
    const byteString = "0x" + Buffer.from(ethers_1.ethers.utils.randomBytes(signed ? bytes - 1 : bytes)).toString("hex");
    return ethers_1.ethers.BigNumber.from(sign + byteString);
}
function randomBytes32() {
    return ethers_1.ethers.utils.hexlify(ethers_1.ethers.utils.randomBytes(32));
}
async function seedWallet(walletToFund, tokens, weth, amountToSeedWith) {
    for (const token of tokens)
        await token.mint(await walletToFund.getAddress(), amountToSeedWith);
    if (weth)
        await weth.connect(walletToFund).deposit({ value: amountToSeedWith });
}
async function seedContract(contract, walletToFund, tokens, weth, amountToSeedWith) {
    await seedWallet(walletToFund, tokens, weth, amountToSeedWith);
    for (const token of tokens)
        await token.connect(walletToFund).transfer(contract.address, amountToSeedWith);
    if (weth)
        await weth.connect(walletToFund).transfer(contract.address, amountToSeedWith);
}
function trimSolanaAddress(bytes32Address) {
    if (!ethers_1.ethers.utils.isHexString(bytes32Address, 32)) {
        throw new Error("Invalid bytes32 address");
    }
    const uint160Address = ethers_1.ethers.BigNumber.from(bytes32Address).mask(160);
    return ethers_1.ethers.utils.hexZeroPad(ethers_1.ethers.utils.hexlify(uint160Address), 20);
}
function hashNonEmptyMessage(message) {
    if (!ethers_1.ethers.utils.isHexString(message) || message.length % 2 !== 0)
        throw new Error("Invalid hex message bytes");
    if (message.length > 2) {
        return ethers_1.ethers.utils.keccak256(message);
    }
    return ethers_1.ethers.utils.hexlify(new Uint8Array(32));
}
const createRandomBytes32 = () => ethers_1.ethers.utils.hexlify(ethers_1.ethers.utils.randomBytes(32));
exports.createRandomBytes32 = createRandomBytes32;
function deepEqualsWithBigNumber(x, y, omitKeys = []) {
    if (x === undefined || y === undefined || x === null || y === null) {
        return false;
    }
    const xObj = x;
    const yObj = y;
    const sortedKeysX = Object.fromEntries(Object.keys(xObj)
        .sort()
        .map((key) => [key, xObj[key]]));
    const sortedKeysY = Object.fromEntries(Object.keys(yObj)
        .sort()
        .map((key) => [key, yObj[key]]));
    chaiAssert.deepStrictEqual(lodash_1.default.omit(sortedKeysX, omitKeys), lodash_1.default.omit(sortedKeysY, omitKeys));
    return true;
}
async function assertPromiseError(promise, errMessage) {
    const SPECIAL_ERROR_MESSAGE = "Promise didn't fail";
    try {
        await promise;
        throw new Error(SPECIAL_ERROR_MESSAGE);
    }
    catch (e) {
        const err = e;
        if (err.message.includes(SPECIAL_ERROR_MESSAGE)) {
            throw err;
        }
        if (errMessage) {
            chaiAssert.isTrue(err.message.includes(errMessage));
        }
    }
}
async function assertPromisePasses(promise) {
    try {
        await promise;
    }
    catch (e) {
        const err = e;
        throw new Error("Promise failed: " + err.message);
    }
}
async function setupTokensForWallet(contractToApprove, wallet, tokens, weth, seedMultiplier = 1) {
    const approveToken = async (token) => {
        const balance = await token.balanceOf(wallet.address);
        await token.connect(wallet).approve(contractToApprove.address, balance);
    };
    await seedWallet(wallet, tokens, weth, constants_2.amountToSeedWallets.mul(seedMultiplier));
    await Promise.all(tokens.map(approveToken));
    if (weth) {
        await approveToken(weth);
    }
}
function createSpyLogger() {
    const spy = sinon_1.default.spy();
    const spyLogger = winston_1.default.createLogger({
        level: "debug",
        format: winston_1.default.format.combine(winston_1.default.format(bigNumberFormatter)(), winston_1.default.format.json()),
        transports: [
            new SpyTransport_1.SpyTransport({ level: "debug" }, { spy }),
            process.env.LOG_IN_TEST ? new winston_1.default.transports.Console() : null,
        ].filter((n) => n),
    });
    return { spy, spyLogger };
}
async function deploySpokePoolWithToken(fromChainId = 0) {
    const { weth, erc20, spokePool, unwhitelistedErc20, destErc20 } = await (0, SpokePool_Fixture_2.deploySpokePool)(hardhat_1.ethers);
    const receipt = await spokePool.deployTransaction.wait();
    await spokePool.setChainId(fromChainId == 0 ? constants_2.originChainId : fromChainId);
    return { weth, erc20, spokePool, unwhitelistedErc20, destErc20, deploymentBlock: receipt.blockNumber };
}
async function deployConfigStore(signer, tokensToAdd, maxL1TokensPerPoolRebalanceLeaf = constants_2.MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF, maxRefundPerRelayerRefundLeaf = constants_2.MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, rateModel = constants_2.sampleRateModel, additionalChainIdIndices) {
    const configStore = (await (await (0, getContractFactory_1.getContractFactory)("AcrossConfigStore", signer)).deploy());
    const { blockNumber: deploymentBlock } = await configStore.deployTransaction.wait();
    for (const token of tokensToAdd) {
        await configStore.updateTokenConfig(token.address, JSON.stringify({
            rateModel: rateModel,
        }));
    }
    await configStore.updateGlobalConfig((0, utils_1.utf8ToHex)(clients_1.GLOBAL_CONFIG_STORE_KEYS.MAX_POOL_REBALANCE_LEAF_SIZE), maxL1TokensPerPoolRebalanceLeaf.toString());
    await configStore.updateGlobalConfig((0, utils_1.utf8ToHex)(clients_1.GLOBAL_CONFIG_STORE_KEYS.MAX_RELAYER_REPAYMENT_LEAF_SIZE), maxRefundPerRelayerRefundLeaf.toString());
    if (additionalChainIdIndices) {
        await configStore.updateGlobalConfig((0, utils_1.utf8ToHex)(clients_1.GLOBAL_CONFIG_STORE_KEYS.CHAIN_ID_INDICES), JSON.stringify([...constants_1.PROTOCOL_DEFAULT_CHAIN_ID_INDICES, ...additionalChainIdIndices]));
    }
    return { configStore, deploymentBlock };
}
async function deployAndConfigureHubPool(signer, spokePools, finderAddress = constants_2.zeroAddress, timerAddress = constants_2.zeroAddress) {
    const lpTokenFactory = await (await (0, getContractFactory_1.getContractFactory)("LpTokenFactory", signer)).deploy();
    const hubPool = await (await (0, getContractFactory_1.getContractFactory)("HubPool", signer)).deploy(lpTokenFactory.address, finderAddress, constants_2.zeroAddress, timerAddress);
    const receipt = await hubPool.deployTransaction.wait();
    const mockAdapter = await (await (0, getContractFactory_1.getContractFactory)("Mock_Adapter", signer)).deploy();
    for (const spokePool of spokePools) {
        await hubPool.setCrossChainContracts(spokePool.l2ChainId, mockAdapter.address, spokePool.spokePool.address);
    }
    const l1Token_1 = await (await (0, getContractFactory_1.getContractFactory)("ExpandedERC20", signer)).deploy("L1Token1", "L1Token1", 18);
    await l1Token_1.addMember(constants_2.TokenRolesEnum.MINTER, signer.address);
    const l1Token_2 = await (await (0, getContractFactory_1.getContractFactory)("ExpandedERC20", signer)).deploy("L1Token2", "L1Token2", 18);
    await l1Token_2.addMember(constants_2.TokenRolesEnum.MINTER, signer.address);
    return { hubPool, mockAdapter, l1Token_1, l1Token_2, hubPoolDeploymentBlock: receipt.blockNumber };
}
async function enableRoutesOnHubPool(hubPool, rebalanceRouteTokens) {
    for (const tkn of rebalanceRouteTokens) {
        await hubPool.setPoolRebalanceRoute(tkn.destinationChainId, tkn.l1Token.address, tkn.destinationToken.address);
        await hubPool.enableL1TokenForLiquidityProvision(tkn.l1Token.address);
    }
}
function appendMessageToResult(body) {
    return { ...body, message: "" };
}
async function getLastBlockTime(provider) {
    return (await provider.getBlock(await provider.getBlockNumber())).timestamp;
}
async function addLiquidity(signer, hubPool, l1Token, amount) {
    await seedWallet(signer, [l1Token], undefined, amount);
    await l1Token.connect(signer).approve(hubPool.address, amount);
    await hubPool.enableL1TokenForLiquidityProvision(l1Token.address);
    await hubPool.connect(signer).addLiquidity(l1Token.address, amount);
}
function deposit(spokePool, destinationChainId, signer, inputToken, inputAmount, outputToken, outputAmount, opts = {}) {
    return _deposit(spokePool, destinationChainId, signer, inputToken, inputAmount, outputToken, outputAmount, {
        ...opts,
        addressModifier: utils_1.toBytes32,
    });
}
function depositV3(spokePool, destinationChainId, signer, inputToken, inputAmount, outputToken, outputAmount, opts = {}) {
    return _deposit(spokePool, destinationChainId, signer, inputToken, inputAmount, outputToken, outputAmount, {
        ...opts,
        addressModifier: utils_1.toEvmAddress,
    });
}
async function _deposit(spokePool, destinationChainId, signer, inputToken, inputAmount, outputToken, outputAmount, opts = {}) {
    const depositor = (0, utils_1.toAddressType)(signer.address, await spokePool.chainId());
    const recipient = opts.recipient ?? depositor;
    const [spokePoolTime, fillDeadlineBuffer] = (await Promise.all([spokePool.getCurrentTime(), spokePool.fillDeadlineBuffer()])).map((n) => Number(n));
    const quoteTimestamp = opts.quoteTimestamp ?? spokePoolTime;
    const message = opts.message ?? constants_1.EMPTY_MESSAGE;
    const fillDeadline = opts.fillDeadline ?? spokePoolTime + fillDeadlineBuffer;
    const exclusivityDeadline = opts.exclusivityDeadline ?? 0;
    const exclusiveRelayer = opts.exclusiveRelayer ?? (0, utils_1.toAddressType)(constants_2.zeroAddress, destinationChainId);
    await spokePool
        .connect(signer)
        .deposit(depositor.toBytes32(), recipient.toBytes32(), inputToken.toBytes32(), outputToken.toBytes32(), inputAmount, outputAmount, destinationChainId, exclusiveRelayer.toBytes32(), quoteTimestamp, fillDeadline, exclusivityDeadline, message);
    const getChainId = async () => Promise.resolve(Number(await spokePool.chainId()));
    const [events, fetchedOriginChainId] = await Promise.all([
        spokePool.queryFilter(spokePool.filters.FundsDeposited()),
        getChainId(),
    ]);
    const lastEvent = events.at(-1);
    let args = lastEvent?.args;
    chaiAssert.exists(args);
    args = args;
    const { blockNumber, transactionHash, transactionIndex, logIndex } = lastEvent;
    (0, assert_1.default)(args.destinationChainId.toNumber() === destinationChainId);
    return {
        depositId: (0, utils_1.toBN)(args.depositId),
        originChainId: fetchedOriginChainId,
        destinationChainId,
        depositor: (0, utils_1.toAddressType)(args.depositor, fetchedOriginChainId),
        recipient: (0, utils_1.toAddressType)(args.recipient, destinationChainId),
        inputToken: (0, utils_1.toAddressType)(args.inputToken, fetchedOriginChainId),
        inputAmount: args.inputAmount,
        outputToken: (0, utils_1.toAddressType)(args.outputToken, destinationChainId),
        outputAmount: args.outputAmount,
        quoteTimestamp: args.quoteTimestamp,
        message: args.message,
        messageHash: (0, utils_1.getMessageHash)(args.message),
        fillDeadline: args.fillDeadline,
        exclusivityDeadline: args.exclusivityDeadline,
        exclusiveRelayer: (0, utils_1.toAddressType)(args.exclusiveRelayer, destinationChainId),
        fromLiteChain: false,
        toLiteChain: false,
        quoteBlockNumber: 0,
        blockNumber,
        txnRef: transactionHash,
        txnIndex: transactionIndex,
        logIndex,
    };
}
async function requestV3SlowFill(spokePool, relayData, signer) {
    const destinationChainId = Number(await spokePool.chainId());
    chaiAssert.notEqual(relayData.originChainId, destinationChainId);
    await spokePool.connect(signer).requestSlowFill({
        ...relayData,
        depositor: relayData.depositor.toBytes32(),
        recipient: relayData.recipient.toBytes32(),
        inputToken: relayData.inputToken.toBytes32(),
        outputToken: relayData.outputToken.toBytes32(),
        exclusiveRelayer: relayData.exclusiveRelayer.toBytes32(),
    });
    const events = await spokePool.queryFilter(spokePool.filters.RequestedSlowFill());
    const lastEvent = events.at(-1);
    (0, chai_1.expect)(lastEvent).to.exist;
    const { blockNumber, transactionHash, transactionIndex, logIndex } = lastEvent;
    (0, chai_1.expect)(lastEvent.args).to.exist;
    const args = lastEvent.args;
    const fetchedOriginChainId = Number(args.originChainId);
    return {
        depositId: (0, utils_1.toBN)(args.depositId),
        originChainId: fetchedOriginChainId,
        destinationChainId,
        depositor: (0, utils_1.toAddressType)(args.depositor, fetchedOriginChainId),
        recipient: (0, utils_1.toAddressType)(args.recipient, destinationChainId),
        inputToken: (0, utils_1.toAddressType)(args.inputToken, fetchedOriginChainId),
        inputAmount: args.inputAmount,
        outputToken: (0, utils_1.toAddressType)(args.outputToken, destinationChainId),
        outputAmount: args.outputAmount,
        messageHash: (0, utils_1.getMessageHash)(args.message),
        fillDeadline: args.fillDeadline,
        exclusivityDeadline: args.exclusivityDeadline,
        exclusiveRelayer: (0, utils_1.toAddressType)(args.exclusiveRelayer, destinationChainId),
        blockNumber,
        txnRef: transactionHash,
        txnIndex: transactionIndex,
        logIndex,
    };
}
async function fillRelay(spokePool, _deposit, signer, repayment) {
    const destinationChainId = Number(await spokePool.chainId());
    chaiAssert.notEqual(_deposit.originChainId, destinationChainId);
    const depositData = {
        ..._deposit,
        depositor: _deposit.depositor.toBytes32(),
        recipient: _deposit.recipient.toBytes32(),
        exclusiveRelayer: _deposit.exclusiveRelayer.toBytes32(),
        inputToken: _deposit.inputToken.toBytes32(),
        outputToken: _deposit.outputToken.toBytes32(),
    };
    const repaymentAddress = repayment?.repaymentAddress.toBytes32() ?? (0, utils_1.toBytes32)(signer.address);
    await spokePool
        .connect(signer)
        .fillRelay(depositData, repayment?.repaymentChainId ?? destinationChainId, repaymentAddress);
    const events = await spokePool.queryFilter(spokePool.filters.FilledRelay());
    const lastEvent = events.at(-1);
    let args = lastEvent.args;
    chaiAssert.exists(args);
    args = args;
    const { blockNumber, transactionHash, transactionIndex, logIndex } = lastEvent;
    return {
        depositId: (0, utils_1.toBN)(args.depositId),
        originChainId: Number(args.originChainId),
        destinationChainId,
        depositor: (0, utils_1.toAddressType)(args.depositor, args.originChainId),
        recipient: (0, utils_1.toAddressType)(args.recipient, destinationChainId),
        inputToken: (0, utils_1.toAddressType)(args.inputToken, args.originChainId),
        inputAmount: args.inputAmount,
        outputToken: (0, utils_1.toAddressType)(args.outputToken, destinationChainId),
        outputAmount: args.outputAmount,
        messageHash: (0, utils_1.getMessageHash)(args.message),
        fillDeadline: args.fillDeadline,
        exclusivityDeadline: args.exclusivityDeadline,
        exclusiveRelayer: (0, utils_1.toAddressType)(args.exclusiveRelayer, destinationChainId),
        relayer: args.relayer,
        repaymentChainId: Number(args.repaymentChainId),
        relayExecutionInfo: {
            updatedRecipient: (0, utils_1.toAddressType)(args.relayExecutionInfo.updatedRecipient, destinationChainId),
            updatedMessageHash: args.relayExecutionInfo.updatedMessageHash,
            updatedOutputAmount: args.relayExecutionInfo.updatedOutputAmount,
            fillType: args.relayExecutionInfo.fillType,
        },
        blockNumber,
        txnRef: transactionHash,
        txnIndex: transactionIndex,
        logIndex,
    };
}
function getLastBlockNumber() {
    return hardhat_1.ethers.provider.getBlockNumber();
}
function convertMockedConfigClient(_client) {
    return true;
}
function bigNumberFormatter(logEntry) {
    try {
        const out = iterativelyReplaceBigNumbers(logEntry);
        if (out !== logEntry)
            Object.getOwnPropertySymbols(logEntry).map((symbol) => (out[symbol] = logEntry[symbol]));
        return out;
    }
    catch {
        return logEntry;
    }
}
const iterativelyReplaceBigNumbers = (obj) => {
    const replacements = Object.entries(obj).map(([key, value]) => {
        if (utils_1.BigNumber.isBigNumber(value))
            return [key, value.toString()];
        else if (typeof value === "object" && value !== null)
            return [key, iterativelyReplaceBigNumbers(value)];
        else
            return [key, value];
    });
    const copyNeeded = replacements.some(([key, value]) => obj[key] !== value);
    return copyNeeded ? Object.fromEntries(replacements) : obj;
};
function buildDepositForRelayerFeeTest(amount, tokenSymbol, originChainId, toChainId) {
    const _inputToken = (0, utils_1.resolveContractFromSymbol)(tokenSymbol, originChainId);
    (0, assert_1.default)((0, utils_1.isDefined)(_inputToken), `${tokenSymbol} not found on ${originChainId}`);
    const inputToken = (0, utils_1.toAddressType)(_inputToken, originChainId);
    const _outputToken = (0, utils_1.resolveContractFromSymbol)(tokenSymbol, toChainId);
    (0, assert_1.default)((0, utils_1.isDefined)(_outputToken), `${tokenSymbol} not found on ${toChainId}`);
    const outputToken = (0, utils_1.toAddressType)(_outputToken, toChainId);
    const currentTime = (0, utils_1.getCurrentTime)();
    const message = constants_1.EMPTY_MESSAGE;
    return {
        depositId: utils_1.bnUint32Max,
        originChainId: originChainId,
        destinationChainId: toChainId,
        depositor: (0, utils_1.toAddressType)((0, constants_2.randomAddress)(), originChainId),
        recipient: (0, utils_1.toAddressType)((0, constants_2.randomAddress)(), toChainId),
        inputToken,
        inputAmount: (0, utils_1.toBN)(amount),
        outputToken,
        outputAmount: (0, utils_1.toBN)(amount).sub(utils_1.bnOne),
        message,
        messageHash: (0, utils_1.getMessageHash)(message),
        quoteTimestamp: currentTime,
        fillDeadline: currentTime + 7200,
        exclusivityDeadline: 0,
        exclusiveRelayer: (0, utils_1.toAddressType)(constants_1.ZERO_ADDRESS, toChainId),
        fromLiteChain: false,
        toLiteChain: false,
    };
}
//# sourceMappingURL=utils.js.map