"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertFillParamsToBytes32 = exports.convertRelayDataParamsToBytes32 = exports.resolveDepositMessage = exports.isDepositSpedUp = exports.isFillOrSlowFillRequestMessageEmpty = exports.isMessageEmpty = exports.isZeroValueFillOrSlowFillRequest = exports.invalidOutputToken = exports.isZeroValueDeposit = exports.validateFillForDeposit = exports.getRelayEventKey = exports.queryHistoricalDepositForFill = exports.InvalidFill = void 0;
var tslib_1 = require("tslib");
var assert_1 = tslib_1.__importDefault(require("assert"));
var constants_1 = require("../constants");
var SpokeUtils_1 = require("./SpokeUtils");
var NetworkUtils_1 = require("./NetworkUtils");
var BigNumberUtils_1 = require("./BigNumberUtils");
var CachingUtils_1 = require("./CachingUtils");
var TimeUtils_1 = require("./TimeUtils");
var TypeGuards_1 = require("./TypeGuards");
var 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 = {}));
function queryHistoricalDepositForFill(spokePoolClient, fill, cache) {
    var _a;
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var depositId, originChain, deposit, match_1, cachedDeposit, result, match;
        return tslib_1.__generator(this, function (_b) {
            switch (_b.label) {
                case 0:
                    if ((0, SpokeUtils_1.isUnsafeDepositId)(fill.depositId)) {
                        return [2, {
                                found: false,
                                code: InvalidFill.DepositIdOutOfRange,
                                reason: "Cannot find historical deposit for fill with unsafe deposit ID ".concat(fill.depositId, "."),
                            }];
                    }
                    if (fill.originChainId !== spokePoolClient.chainId) {
                        throw new Error("OriginChainId mismatch (".concat(fill.originChainId, " != ").concat(spokePoolClient.chainId, ")"));
                    }
                    if (!spokePoolClient.isUpdated) {
                        throw new Error("SpokePoolClient must be updated before querying historical deposits");
                    }
                    depositId = fill.depositId;
                    originChain = (0, NetworkUtils_1.getNetworkName)(fill.originChainId);
                    deposit = spokePoolClient.getDeposit(depositId);
                    if ((0, TypeGuards_1.isDefined)(deposit)) {
                        match_1 = validateFillForDeposit(fill, deposit);
                        if (match_1.valid) {
                            return [2, { found: true, deposit: deposit }];
                        }
                        return [2, {
                                found: false,
                                code: InvalidFill.FillMismatch,
                                reason: "Fill for ".concat(originChain, " deposit ID ").concat(depositId.toString(), " is invalid (").concat(match_1.reason, ")."),
                            }];
                    }
                    if (!cache) return [3, 2];
                    return [4, (0, CachingUtils_1.getDepositInCache)((0, CachingUtils_1.getDepositKey)(fill), cache)];
                case 1:
                    cachedDeposit = _b.sent();
                    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: fill,
                            cachedDeposit: cachedDeposit,
                        });
                        cachedDeposit = undefined;
                    }
                    _b.label = 2;
                case 2:
                    if (!(0, TypeGuards_1.isDefined)(cachedDeposit)) return [3, 3];
                    deposit = cachedDeposit;
                    return [3, 6];
                case 3: return [4, spokePoolClient.findDeposit(fill.depositId)];
                case 4:
                    result = _b.sent();
                    if (!result.found) {
                        return [2, result];
                    }
                    (deposit = result.deposit);
                    if (!cache) return [3, 6];
                    return [4, (0, CachingUtils_1.setDepositInCache)(deposit, (0, TimeUtils_1.getCurrentTime)(), cache, constants_1.DEFAULT_CACHING_TTL)];
                case 5:
                    _b.sent();
                    _b.label = 6;
                case 6:
                    (0, assert_1.default)((0, TypeGuards_1.isDefined)(deposit), "Unexpectedly failed to locate ".concat(originChain, " deposit ").concat(fill.depositId));
                    (_a = deposit.messageHash) !== null && _a !== void 0 ? _a : (deposit.messageHash = (0, SpokeUtils_1.getMessageHash)(deposit.message));
                    match = validateFillForDeposit(fill, deposit);
                    if (match.valid) {
                        return [2, { found: true, deposit: deposit }];
                    }
                    return [2, {
                            found: false,
                            code: InvalidFill.FillMismatch,
                            reason: match.reason,
                        }];
            }
        });
    });
}
exports.queryHistoricalDepositForFill = queryHistoricalDepositForFill;
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("-");
}
exports.getRelayEventKey = getRelayEventKey;
var 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" };
    }
    var invalidKey = RELAYDATA_KEYS.find(function (key) { return 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: "".concat(invalidKey, " mismatch (").concat(relayData[invalidKey], " != ").concat(deposit[invalidKey], ")") }
        : { valid: true };
}
exports.validateFillForDeposit = validateFillForDeposit;
function isZeroValueDeposit(deposit) {
    return deposit.inputAmount.eq(0) && isMessageEmpty(deposit.message);
}
exports.isZeroValueDeposit = isZeroValueDeposit;
function invalidOutputToken(deposit) {
    return deposit.outputToken.isZeroAddress();
}
exports.invalidOutputToken = invalidOutputToken;
function isZeroValueFillOrSlowFillRequest(e) {
    return e.inputAmount.eq(BigNumberUtils_1.bnZero) && e.messageHash === constants_1.ZERO_BYTES;
}
exports.isZeroValueFillOrSlowFillRequest = isZeroValueFillOrSlowFillRequest;
function isMessageEmpty(message) {
    if (message === void 0) { message = constants_1.EMPTY_MESSAGE; }
    return message === "" || message === "0x";
}
exports.isMessageEmpty = isMessageEmpty;
function isFillOrSlowFillRequestMessageEmpty(message) {
    return isMessageEmpty(message) || message === constants_1.ZERO_BYTES;
}
exports.isFillOrSlowFillRequestMessageEmpty = isFillOrSlowFillRequestMessageEmpty;
function isDepositSpedUp(deposit) {
    return (0, TypeGuards_1.isDefined)(deposit.speedUpSignature) && (0, TypeGuards_1.isDefined)(deposit.updatedOutputAmount);
}
exports.isDepositSpedUp = isDepositSpedUp;
function resolveDepositMessage(deposit) {
    var message = isDepositSpedUp(deposit) ? deposit.updatedMessage : deposit.message;
    (0, assert_1.default)((0, TypeGuards_1.isDefined)(message));
    return message;
}
exports.resolveDepositMessage = resolveDepositMessage;
function convertRelayDataParamsToBytes32(relayData) {
    return tslib_1.__assign(tslib_1.__assign({}, relayData), { depositor: relayData.depositor.toBytes32(), recipient: relayData.recipient.toBytes32(), inputToken: relayData.inputToken.toBytes32(), outputToken: relayData.outputToken.toBytes32(), exclusiveRelayer: relayData.exclusiveRelayer.toBytes32() });
}
exports.convertRelayDataParamsToBytes32 = convertRelayDataParamsToBytes32;
function convertFillParamsToBytes32(fill) {
    return tslib_1.__assign(tslib_1.__assign({}, 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: tslib_1.__assign(tslib_1.__assign({}, fill.relayExecutionInfo), { updatedRecipient: fill.relayExecutionInfo.updatedRecipient.toBytes32() }) });
}
exports.convertFillParamsToBytes32 = convertFillParamsToBytes32;
//# sourceMappingURL=DepositUtils.js.map