"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InvalidFill = void 0;
exports.queryHistoricalDepositForFill = queryHistoricalDepositForFill;
exports.getRelayEventKey = getRelayEventKey;
exports.validateFillForDeposit = validateFillForDeposit;
exports.isZeroValueDeposit = isZeroValueDeposit;
exports.invalidOutputToken = invalidOutputToken;
exports.isZeroValueFillOrSlowFillRequest = isZeroValueFillOrSlowFillRequest;
exports.isMessageEmpty = isMessageEmpty;
exports.isFillOrSlowFillRequestMessageEmpty = isFillOrSlowFillRequestMessageEmpty;
exports.isDepositSpedUp = isDepositSpedUp;
exports.resolveDepositMessage = resolveDepositMessage;
exports.convertRelayDataParamsToBytes32 = convertRelayDataParamsToBytes32;
exports.convertFillParamsToBytes32 = convertFillParamsToBytes32;
exports.convertRelayDataParamsToNative = convertRelayDataParamsToNative;
exports.convertFillParamsToNative = convertFillParamsToNative;
const tslib_1 = require("tslib");
const assert_1 = tslib_1.__importDefault(require("assert"));
const constants_1 = require("../constants");
const SpokeUtils_1 = require("./SpokeUtils");
const NetworkUtils_1 = require("./NetworkUtils");
const BigNumberUtils_1 = require("./BigNumberUtils");
const CachingUtils_1 = require("./CachingUtils");
const TimeUtils_1 = require("./TimeUtils");
const TypeGuards_1 = require("./TypeGuards");
const ValidatorUtils_1 = require("./ValidatorUtils");
var InvalidFill;
(function (InvalidFill) {
    InvalidFill[InvalidFill["DepositIdInvalid"] = 0] = "DepositIdInvalid";
    InvalidFill[InvalidFill["DepositIdNotFound"] = 1] = "DepositIdNotFound";
    InvalidFill[InvalidFill["FillMismatch"] = 2] = "FillMismatch";
    InvalidFill[InvalidFill["DepositIdOutOfRange"] = 3] = "DepositIdOutOfRange";
})(InvalidFill || (exports.InvalidFill = InvalidFill = {}));
async function queryHistoricalDepositForFill(spokePoolClient, fill, cache) {
    if ((0, SpokeUtils_1.isUnsafeDepositId)(fill.depositId)) {
        return {
            found: false,
            code: InvalidFill.DepositIdOutOfRange,
            reason: `Cannot find historical deposit for fill with unsafe deposit ID ${fill.depositId}.`,
        };
    }
    if (fill.originChainId !== spokePoolClient.chainId) {
        throw new Error(`OriginChainId mismatch (${fill.originChainId} != ${spokePoolClient.chainId})`);
    }
    if (!spokePoolClient.isUpdated) {
        throw new Error("SpokePoolClient must be updated before querying historical deposits");
    }
    const { depositId } = fill;
    const originChain = (0, NetworkUtils_1.getNetworkName)(fill.originChainId);
    let deposit = spokePoolClient.getDeposit(depositId);
    if ((0, TypeGuards_1.isDefined)(deposit)) {
        const match = validateFillForDeposit(fill, deposit);
        if (match.valid) {
            return { found: true, deposit };
        }
        return {
            found: false,
            code: InvalidFill.FillMismatch,
            reason: `Fill for ${originChain} deposit ID ${depositId.toString()} is invalid (${match.reason}).`,
        };
    }
    let cachedDeposit;
    if (cache) {
        cachedDeposit = await (0, CachingUtils_1.getDepositInCache)((0, CachingUtils_1.getDepositKey)(fill), cache);
        if ((0, TypeGuards_1.isDefined)(cachedDeposit) && !(0, ValidatorUtils_1.isDepositFormedCorrectly)(cachedDeposit)) {
            spokePoolClient.logger.warn({
                at: "[SDK]:DepositUtils#queryHistoricalDepositForFill",
                message: "Cached deposit was not formed correctly, removing from cache",
                fill,
                cachedDeposit,
            });
            cachedDeposit = undefined;
        }
    }
    if ((0, TypeGuards_1.isDefined)(cachedDeposit)) {
        deposit = cachedDeposit;
    }
    else {
        const result = await spokePoolClient.findDeposit(fill.depositId);
        if (!result.found) {
            return result;
        }
        ({ deposit } = result);
        if (cache) {
            await (0, CachingUtils_1.setDepositInCache)(deposit, (0, TimeUtils_1.getCurrentTime)(), cache, constants_1.DEFAULT_CACHING_TTL);
        }
    }
    (0, assert_1.default)((0, TypeGuards_1.isDefined)(deposit), `Unexpectedly failed to locate ${originChain} deposit ${fill.depositId}`);
    deposit.messageHash ??= (0, SpokeUtils_1.getMessageHash)(deposit.message);
    const match = validateFillForDeposit(fill, deposit);
    if (match.valid) {
        return { found: true, deposit: deposit };
    }
    return {
        found: false,
        code: InvalidFill.FillMismatch,
        reason: match.reason,
    };
}
function getRelayEventKey(data) {
    return [
        data.depositor,
        data.recipient,
        data.exclusiveRelayer,
        data.inputToken,
        data.outputToken,
        data.inputAmount,
        data.outputAmount,
        data.originChainId,
        data.destinationChainId,
        data.depositId,
        data.fillDeadline,
        data.exclusivityDeadline,
        data.messageHash,
    ]
        .map(String)
        .join("-");
}
const RELAYDATA_KEYS = [
    "depositId",
    "originChainId",
    "destinationChainId",
    "depositor",
    "recipient",
    "inputToken",
    "inputAmount",
    "outputToken",
    "outputAmount",
    "fillDeadline",
    "exclusivityDeadline",
    "exclusiveRelayer",
    "messageHash",
];
function validateFillForDeposit(relayData, deposit) {
    if (deposit === undefined) {
        return { valid: false, reason: "Deposit is undefined" };
    }
    let invalidKey = RELAYDATA_KEYS.find((key) => relayData[key].toString() !== deposit[key].toString());
    if (!(0, TypeGuards_1.isDefined)(invalidKey) && [relayData.messageHash, deposit.messageHash].includes(constants_1.UNDEFINED_MESSAGE_HASH)) {
        invalidKey = "messageHash";
    }
    return (0, TypeGuards_1.isDefined)(invalidKey)
        ? { valid: false, reason: `${invalidKey} mismatch (${relayData[invalidKey]} != ${deposit[invalidKey]})` }
        : { valid: true };
}
function isZeroValueDeposit(deposit) {
    return deposit.inputAmount.eq(0) && isMessageEmpty(deposit.message);
}
function invalidOutputToken(deposit) {
    return deposit.outputToken.isZeroAddress();
}
function isZeroValueFillOrSlowFillRequest(e) {
    return e.inputAmount.eq(BigNumberUtils_1.bnZero) && e.messageHash === constants_1.ZERO_BYTES;
}
function isMessageEmpty(message = constants_1.EMPTY_MESSAGE) {
    return message === "" || message === "0x";
}
function isFillOrSlowFillRequestMessageEmpty(message) {
    return isMessageEmpty(message) || message === constants_1.ZERO_BYTES;
}
function isDepositSpedUp(deposit) {
    return (0, TypeGuards_1.isDefined)(deposit.speedUpSignature) && (0, TypeGuards_1.isDefined)(deposit.updatedOutputAmount);
}
function resolveDepositMessage(deposit) {
    const message = isDepositSpedUp(deposit) ? deposit.updatedMessage : deposit.message;
    (0, assert_1.default)((0, TypeGuards_1.isDefined)(message));
    return message;
}
function convertRelayDataParamsToBytes32(relayData) {
    return {
        ...relayData,
        depositor: relayData.depositor.toBytes32(),
        recipient: relayData.recipient.toBytes32(),
        inputToken: relayData.inputToken.toBytes32(),
        outputToken: relayData.outputToken.toBytes32(),
        exclusiveRelayer: relayData.exclusiveRelayer.toBytes32(),
    };
}
function convertFillParamsToBytes32(fill) {
    return {
        ...fill,
        depositor: fill.depositor.toBytes32(),
        recipient: fill.recipient.toBytes32(),
        inputToken: fill.inputToken.toBytes32(),
        outputToken: fill.outputToken.toBytes32(),
        exclusiveRelayer: fill.exclusiveRelayer.toBytes32(),
        relayer: fill.relayer.toBytes32(),
        relayExecutionInfo: {
            ...fill.relayExecutionInfo,
            updatedRecipient: fill.relayExecutionInfo.updatedRecipient.toBytes32(),
        },
    };
}
function convertRelayDataParamsToNative(relayData) {
    return {
        ...relayData,
        depositor: relayData.depositor.toNative(),
        recipient: relayData.recipient.toNative(),
        inputToken: relayData.inputToken.toNative(),
        outputToken: relayData.outputToken.toNative(),
        exclusiveRelayer: relayData.exclusiveRelayer.toNative(),
    };
}
function convertFillParamsToNative(fill) {
    return {
        ...fill,
        depositor: fill.depositor.toNative(),
        recipient: fill.recipient.toNative(),
        inputToken: fill.inputToken.toNative(),
        outputToken: fill.outputToken.toNative(),
        exclusiveRelayer: fill.exclusiveRelayer.toNative(),
        relayer: fill.relayer.toNative(),
        relayExecutionInfo: {
            ...fill.relayExecutionInfo,
            updatedRecipient: fill.relayExecutionInfo.updatedRecipient.toNative(),
        },
    };
}
//# sourceMappingURL=DepositUtils.js.map